diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,61 @@
 User-visible changes in the hledger command line tool.
 
 
+# 1.11 (2018/9/30)
+
+* The default display order of accounts is now influenced by
+  the order of account directives. Accounts declared by account
+  directives are displayed first (top-most), in declaration order,
+  followed by undeclared accounts in alphabetical order. Numeric
+  account codes are no longer used, and are ignored and considered
+  deprecated.
+
+  So if your accounts are displaying in a weird order after upgrading,
+  and you want them alphabetical like before, just sort your account
+  directives alphabetically.
+
+* Account sorting (by name, by declaration, by amount) is now more
+  robust and supported consistently by all commands (accounts,
+  balance, bs..) in all modes (tree & flat, tabular & non-tabular).
+
+* close: new --opening/--closing flags to print only the opening or
+  closing transaction
+
+* files: a new command to list included files
+
+* prices: query arguments are now supported. Prices can be filtered by
+  date, and postings providing transaction prices can also be filtered.
+
+* rewrite: help clarifies relation to print --auto (#745)
+
+* roi: a new command to compute return on investment, based on hledger-irr
+
+* test: has more verbose output, more informative failure messages,
+  and no longer tries to read the journal
+
+* csv: We use a more robust CSV lib (cassava) and now support
+  non-comma separators, eg --separator ';' (experimental, this flag
+  will probably become a CSV rule) (#829)
+
+* csv: interpolated field names in values are now properly case insensitive, so
+  this works:
+
+  fields  ...,Transaction_Date,...
+  date %Transaction_Date
+
+* journal: D (default commodity) directives no longer break multiplier
+  amounts in transaction modifiers (AKA automated postings) (#860)
+
+* journal: "Automated Postings" have been renamed to "Transaction Modifiers".
+
+* journal: transaction comments in transaction modifier rules are now parsed correctly. (#745)
+
+* journal: when include files form a cycle, we give an error instead
+  of hanging.
+
+* upper-case day/month names in period expressions no longer give an error (#847, #852)
+
+
 # 1.10 (2018/6/30)
 
 * journal: many parse error messages have become more informative, and
diff --git a/Hledger/Cli.hs b/Hledger/Cli.hs
--- a/Hledger/Cli.hs
+++ b/Hledger/Cli.hs
@@ -15,8 +15,8 @@
                      module Hledger.Cli.DocFiles,
                      module Hledger.Cli.Utils,
                      module Hledger.Cli.Version,
-                     tests_Hledger_Cli,
                      module Hledger,
+                     tests_Cli,
                      module System.Console.CmdArgs.Explicit
               )
 where
@@ -29,4 +29,7 @@
 import Hledger.Cli.Utils
 import Hledger.Cli.Version
 
-tests_Hledger_Cli = tests_Hledger_Cli_Commands
+tests_Cli = tests "Cli" [
+   tests_Hledger
+  ,tests_Commands
+ ]
diff --git a/Hledger/Cli/CliOptions.hs b/Hledger/Cli/CliOptions.hs
--- a/Hledger/Cli/CliOptions.hs
+++ b/Hledger/Cli/CliOptions.hs
@@ -60,13 +60,9 @@
   hledgerAddons,
   topicForMode,
 
-  -- * Tests
-  tests_Hledger_Cli_CliOptions,
-
 --  -- * Convenience re-exports
 --  module Data.String.Here,
 --  module System.Console.CmdArgs.Explicit,
---  module Test.HUnit
 )
 where
 
@@ -96,7 +92,6 @@
 import System.Environment
 import System.Exit (exitSuccess)
 import System.FilePath
-import Test.HUnit
 import Text.Megaparsec
 import Text.Megaparsec.Char
 
@@ -125,6 +120,7 @@
 inputflags = [
   flagReq  ["file","f"]      (\s opts -> Right $ setopt "file" s opts) "FILE" "use a different input file. For stdin, use - (default: $LEDGER_FILE or $HOME/.hledger.journal)"
  ,flagReq  ["rules-file"]    (\s opts -> Right $ setopt "rules-file" s opts) "RFILE" "CSV conversion rules file (default: FILE.rules)"
+ ,flagReq  ["separator"]     (\s opts -> Right $ setopt "separator" s opts) "SEPARATOR" "CSV separator (default: ,)"
  ,flagReq  ["alias"]         (\s opts -> Right $ setopt "alias" s opts)  "OLD=NEW" "rename accounts named OLD to NEW"
  ,flagNone ["anon"]          (setboolopt "anon") "anonymize accounts and payees"
  ,flagReq  ["pivot"]         (\s opts -> Right $ setopt "pivot" s opts)  "TAGNAME" "use some other field/tag for account names"
@@ -282,6 +278,7 @@
   ,("vty", "start the curses-style interface")
   ,("web", "start the web interface")
   ,("accounts", "list account names")
+  ,("files", "list included files")
   ,("balance-csv", "output a balance report as CSV")
   ,("close", "show a transaction entry zeroing all accounts")
   ,("print-unique", "print only transactions with unique descriptions")
@@ -707,9 +704,3 @@
 --     d <- getCurrentDay
 --     putStrLn $ "search query: " ++ (show $ queryFromOpts d $ reportopts_ opts)
 
--- tests
-
-tests_Hledger_Cli_CliOptions :: Test
-tests_Hledger_Cli_CliOptions = TestList
- [
- ]
diff --git a/Hledger/Cli/Commands.hs b/Hledger/Cli/Commands.hs
--- a/Hledger/Cli/Commands.hs
+++ b/Hledger/Cli/Commands.hs
@@ -8,10 +8,11 @@
 
 module Hledger.Cli.Commands (
    findCommand
+  ,testcmd
   ,builtinCommands
   ,builtinCommandNames
   ,printCommandsList
-  ,tests_Hledger_Cli_Commands
+  ,tests_Commands
   ,module Hledger.Cli.Commands.Accounts
   ,module Hledger.Cli.Commands.Activity
   ,module Hledger.Cli.Commands.Add
@@ -36,7 +37,6 @@
 ) 
 where
 
-import Control.Monad
 import Data.Default
 import Data.List
 import Data.List.Split (splitOn)
@@ -47,11 +47,11 @@
 import Data.Text (Text)
 import qualified Data.Text as T
 import Data.Time.Calendar
+import qualified EasyTest
 import System.Console.CmdArgs.Explicit as C
 import System.Exit
-import Test.HUnit
 
-import Hledger
+import Hledger 
 import Hledger.Cli.CliOptions
 import Hledger.Cli.Version
 import Hledger.Cli.Commands.Accounts
@@ -64,6 +64,7 @@
 import Hledger.Cli.Commands.Checkdates
 import Hledger.Cli.Commands.Checkdupes
 import Hledger.Cli.Commands.Close
+import Hledger.Cli.Commands.Files
 import Hledger.Cli.Commands.Help
 import Hledger.Cli.Commands.Import
 import Hledger.Cli.Commands.Incomestatement
@@ -73,6 +74,7 @@
 import Hledger.Cli.Commands.Register
 import Hledger.Cli.Commands.Registermatch
 import Hledger.Cli.Commands.Rewrite
+import Hledger.Cli.Commands.Roi
 import Hledger.Cli.Commands.Stats
 import Hledger.Cli.Commands.Tags
 
@@ -93,6 +95,7 @@
   ,(closemode              , close)
   ,(helpmode               , help')
   ,(importmode             , importcmd)
+  ,(filesmode              , files)
   ,(incomestatementmode    , incomestatement)
   ,(pricesmode             , prices)
   ,(printmode              , print')
@@ -100,6 +103,7 @@
   ,(registermode           , register)
   ,(registermatchmode      , registermatch)
   ,(rewritemode            , rewrite)
+  ,(roimode                , roi)
   ,(statsmode              , stats)
   ,(tagsmode               , tags)
   ,(testmode               , testcmd)
@@ -213,116 +217,98 @@
   concatMap (splitOn "|") [w | ' ':l <- lines s, let w:_ = words l]
 
 
-
--- The test command, defined here so it can access other commands' tests.
+-- The test command, defined here for easy access to other modules' tests.
 
-testmode = (defCommandMode ["test"]) {
-  modeHelp = "run built-in self-tests"
- ,modeArgs = ([], Just $ argsFlag "[REGEXPS]")
- ,modeGroupFlags = Group {
-     groupUnnamed = []
-    ,groupHidden = [
-        flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show tests hierarchically"
-       ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show tests as a flat list"
-      ]
-    ,groupNamed = [generalflagsgroup3]
-    }
- }
+testmode = hledgerCommandMode
+  [here| test
+Run the unit tests built in to hledger-lib and hledger, 
+printing results on stdout and exiting with success or failure.
 
--- | Run some or all hledger-lib and hledger unit tests, and exit with success or failure.
-testcmd :: CliOpts -> Journal -> IO ()
-testcmd opts _ = do
-  let ts = 
-        (if tree_ $ reportopts_ opts then matchedTestsTree else matchedTestsFlat) 
-          opts tests_Hledger_Cli_Commands
-  results <- liftM (fst . flip (,) 0) $ runTestTT ts
-  if errors results > 0 || failures results > 0
-    then exitFailure
-    else exitWith ExitSuccess
+If a scope argument is provided, only tests in that (exact, case-sensitive) 
+scope are run.
 
--- | All or pattern-matched tests, as a flat list to show simple names.
-matchedTestsFlat opts = TestList . 
-  filter (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . T.pack . testName) . 
-  flattenTests
+If a numeric second argument is provided, it will set the randomness seed,
+for any tests which use randomness.
 
--- | All or pattern-matched tests, in the original suites to show hierarchical names.
-matchedTestsTree opts = 
-  filterTests (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . T.pack . testName) 
+FLAGS
+  |]
+  []
+  [generalflagsgroup3]
+  []
+  ([], Just $ argsFlag "[TESTPATTERN] [SEED]")
 
+-- | See testmode.
+--
+-- Unlike other hledger commands, this one does not operate on the user's Journal.
+-- For ease of implementation the Journal parameter remains in the type signature. 
+testcmd :: CliOpts -> Journal -> IO ()
+testcmd opts _undefined = do 
+  let args = words' $ query_ $ reportopts_ opts
+  e <- runEasytests args $ EasyTest.tests [tests_Hledger, tests_Commands]
+  if e then exitFailure else exitSuccess
 
--- collected hledger-lib + hledger unit tests
+-- unit tests of hledger command-line executable
 
-tests_Hledger_Cli_Commands :: Test
-tests_Hledger_Cli_Commands = TestList [
-   tests_Hledger
-  ,tests_Hledger_Cli_CliOptions
-  -- ,tests_Hledger_Cli_Commands_Activity
-  -- ,tests_Hledger_Cli_Commands_Add
-  ,tests_Hledger_Cli_Commands_Balance
-  ,tests_Hledger_Cli_Commands_Balancesheet
-  ,tests_Hledger_Cli_Commands_Cashflow
-  ,tests_Hledger_Cli_Commands_Incomestatement
-  ,tests_Hledger_Cli_Commands_Print
-  ,tests_Hledger_Cli_Commands_Register
-  -- ,tests_Hledger_Cli_Commands_Stats
+tests_Commands = tests "Commands" [
+   tests_Balance
+  ,tests_Register
 
   -- some more tests easiest to define here:
   
-  ,"apply account directive" ~: 
-    let ignoresourcepos j = j{jtxns=map (\t -> t{tsourcepos=nullsourcepos}) (jtxns j)} in
-    let sameParse str1 str2 = do j1 <- readJournal def Nothing str1 >>= either error' (return . ignoresourcepos)
-                                 j2 <- readJournal def Nothing str2 >>= either error' (return . ignoresourcepos)
+  ,test "apply account directive" $ do 
+    let ignoresourcepos j = j{jtxns=map (\t -> t{tsourcepos=nullsourcepos}) (jtxns j)}
+    let sameParse str1 str2 = do j1 <- io $ readJournal def Nothing str1 >>= either error' (return . ignoresourcepos)
+                                 j2 <- io $ readJournal def Nothing str2 >>= either error' (return . ignoresourcepos)
                                  j1 `is` j2{jlastreadtime=jlastreadtime j1, jfiles=jfiles j1} --, jparsestate=jparsestate j1}
-    in sameParse
-                         ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
-                          "apply account outer\n2008/12/07 Two\n  aigh  $-2\n  bee  $2\n" <>
-                          "apply account inner\n2008/12/07 Three\n  gamma  $-3\n  delta  $3\n" <>
-                          "end apply account\n2008/12/07 Four\n  why  $-4\n  zed  $4\n" <>
-                          "end apply account\n2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
-                         )
-                         ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
-                          "2008/12/07 Two\n  outer:aigh  $-2\n  outer:bee  $2\n" <>
-                          "2008/12/07 Three\n  outer:inner:gamma  $-3\n  outer:inner:delta  $3\n" <>
-                          "2008/12/07 Four\n  outer:why  $-4\n  outer:zed  $4\n" <>
-                          "2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
-                         )
+    sameParse
+     ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
+      "apply account outer\n2008/12/07 Two\n  aigh  $-2\n  bee  $2\n" <>
+      "apply account inner\n2008/12/07 Three\n  gamma  $-3\n  delta  $3\n" <>
+      "end apply account\n2008/12/07 Four\n  why  $-4\n  zed  $4\n" <>
+      "end apply account\n2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
+     )
+     ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
+      "2008/12/07 Two\n  outer:aigh  $-2\n  outer:bee  $2\n" <>
+      "2008/12/07 Three\n  outer:inner:gamma  $-3\n  outer:inner:delta  $3\n" <>
+      "2008/12/07 Four\n  outer:why  $-4\n  outer:zed  $4\n" <>
+      "2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
+     )
 
-  ,"apply account directive should preserve \"virtual\" posting type" ~: do
-    j <- readJournal def Nothing "apply account test\n2008/12/07 One\n  (from)  $-1\n  (to)  $1\n" >>= either error' return
+  ,test "apply account directive should preserve \"virtual\" posting type" $ do
+    j <- io $ readJournal def Nothing "apply account test\n2008/12/07 One\n  (from)  $-1\n  (to)  $1\n" >>= either error' return
     let p = head $ tpostings $ head $ jtxns j
-    assertBool "" $ paccount p == "test:from"
-    assertBool "" $ ptype p == VirtualPosting
+    paccount p `is` "test:from"
+    ptype p `is` VirtualPosting
   
-  ,"account aliases" ~: do
-    j <- readJournal def Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" >>= either error' return
+  ,test "account aliases" $ do
+    j <- io $ readJournal def Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" >>= either error' return
     let p = head $ tpostings $ head $ jtxns j
-    assertBool "" $ paccount p == "equity:draw:personal:food"
+    paccount p `is` "equity:draw:personal:food"
 
-  ,"ledgerAccountNames" ~:
+  ,test "ledgerAccountNames" $
     ledgerAccountNames ledger7 `is`
      ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",
       "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation",
       "liabilities","liabilities:credit cards","liabilities:credit cards:discover"]
 
-  -- ,"journalCanonicaliseAmounts" ~:
+  -- ,test "journalCanonicaliseAmounts" ~:
   --  "use the greatest precision" ~:
   --   (map asprecision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2]
 
   -- don't know what this should do
-  -- ,"elideAccountName" ~: do
+  -- ,test "elideAccountName" ~: do
   --    (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"
   --     `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa")
   --    (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"
   --     `is` "aa:aa:aaaaaaaaaaaaaa")
 
-  ,"default year" ~: do
-    j <- readJournal def Nothing defaultyear_journal_txt >>= either error' return
+  ,test "default year" $ do
+    j <- io $ readJournal def Nothing defaultyear_journal_txt >>= either error' return
     tdate (head $ jtxns j) `is` fromGregorian 2009 1 1
-    return ()
 
-  ,"show dollars" ~: showAmount (usd 1) ~?= "$1.00"
+  ,test "show dollars" $ showAmount (usd 1) `is` "$1.00"
 
-  ,"show hours" ~: showAmount (hrs 1) ~?= "1.00h"
+  ,test "show hours" $ showAmount (hrs 1) `is` "1.00h"
 
  ]
 
diff --git a/Hledger/Cli/Commands/Accounts.hs b/Hledger/Cli/Commands/Accounts.hs
--- a/Hledger/Cli/Commands/Accounts.hs
+++ b/Hledger/Cli/Commands/Accounts.hs
@@ -10,27 +10,25 @@
 
 -}
 
+{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE CPP #-}
 
 module Hledger.Cli.Commands.Accounts (
   accountsmode
  ,accounts
- ,tests_Hledger_Cli_Commands_Accounts
 ) where
 
-import Data.List
 #if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
 #endif
--- import Data.Text (Text)
+import Data.List
 import qualified Data.Text as T
+import qualified Data.Text.IO as T
 import System.Console.CmdArgs.Explicit as C
-import Test.HUnit
 
 import Hledger
-import Prelude hiding (putStrLn)
-import Hledger.Utils.UTF8IOCompat (putStrLn)
 import Hledger.Cli.CliOptions
 
 
@@ -51,6 +49,7 @@
      groupUnnamed = [
       flagNone ["declared"] (\opts -> setboolopt "declared" opts) "show account names declared with account directives"
      ,flagNone ["used"] (\opts -> setboolopt "used" opts) "show account names referenced by transactions"
+     ,flagNone ["codes"] (\opts -> setboolopt "codes" opts) "also show numeric account codes"
      ,flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show short account names, as a tree"
      ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show full account names, as a list (default)"
      ,flagReq  ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "flat mode: omit N leading account name parts"
@@ -64,22 +63,39 @@
 -- | The accounts command.
 accounts :: CliOpts -> Journal -> IO ()
 accounts CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
+
+  -- 1. identify the accounts we'll show
   d <- getCurrentDay
-  let q = queryFromOpts d ropts
+  let tree     = tree_ ropts
+      declared = boolopt "declared" rawopts
+      used     = boolopt "used"     rawopts
+      q        = queryFromOpts d ropts
+      -- a depth limit will clip and exclude account names later, but should not exclude accounts at this stage
       nodepthq = dbg1 "nodepthq" $ filterQuery (not . queryIsDepth) q
       depth    = dbg1 "depth" $ queryDepth $ filterQuery queryIsDepth q
-      matcheddeclaredaccts = dbg1 "matcheddeclaredaccts" $ nub $ sort $ filter (matchesAccount q) $ map fst $ jaccounts j
-      matchedps = dbg1 "ps" $ journalPostings $ filterJournalPostings nodepthq j
-      matchedusedaccts = dbg1 "matchedusedaccts" $ nub $ sort $ filter (not . T.null) $ map (clipAccountName depth) $ map paccount matchedps
-      used     = boolopt "used"   rawopts
-      declared = boolopt "declared" rawopts
-      as | declared     && not used = matcheddeclaredaccts
-         | not declared && used     = matchedusedaccts
-         | otherwise                = nub $ sort $ matcheddeclaredaccts ++ matchedusedaccts
-      as' | tree_ ropts = expandAccountNames as
-          | otherwise   = as
-      render a | tree_ ropts = T.replicate (2 * (accountNameLevel a - 1)) " " <> accountLeafName a
-               | otherwise   = maybeAccountNameDrop ropts a
-  mapM_ (putStrLn . T.unpack . render) as'
+      matcheddeclaredaccts = dbg1 "matcheddeclaredaccts" $ filter (matchesAccount nodepthq) $ jdeclaredaccounts j
+      matchedusedaccts     = dbg5 "matchedusedaccts" $ map paccount $ journalPostings $ filterJournalPostings nodepthq j
+      accts                = dbg5 "accts to show" $ -- no need to nub/sort, accountTree will
+        if | declared     && not used -> matcheddeclaredaccts
+           | not declared && used     -> matchedusedaccts
+           | otherwise                -> matcheddeclaredaccts ++ matchedusedaccts 
 
-tests_Hledger_Cli_Commands_Accounts = TestList []
+  -- 2. sort them by declaration order and name, at each level of their tree structure
+      sortedaccts = sortAccountNamesByDeclaration j tree accts
+
+  -- 3. if there's a depth limit, depth-clip and remove any no longer useful items 
+      clippedaccts =
+        dbg1 "clippedaccts" $
+        filter (matchesAccount q) $    -- clipping can leave accounts that no longer visibly match the query
+        nub $                          -- clipping can leave duplicates (adjacent, hopefully)
+        filter (not . T.null) $        -- depth:0 can leave nulls
+        map (clipAccountName depth) $  -- clip at depth if specified 
+        sortedaccts 
+
+  -- 4. print what remains as a list or tree, maybe applying --drop in the former case 
+  mapM_ (T.putStrLn . render) clippedaccts
+    where
+      render a 
+        | tree_ ropts = T.replicate (2 * (accountNameLevel a - 1)) " " <> accountLeafName a
+        | otherwise   = maybeAccountNameDrop ropts a
+
diff --git a/Hledger/Cli/Commands/Add.hs b/Hledger/Cli/Commands/Add.hs
--- a/Hledger/Cli/Commands/Add.hs
+++ b/Hledger/Cli/Commands/Add.hs
@@ -120,7 +120,7 @@
 -- most similar recent transaction in the journal.
 getAndAddTransactions :: EntryState -> IO ()
 getAndAddTransactions es@EntryState{..} = (do
-  mt <- runInputT (setComplete noCompletion defaultSettings) (run $ haskeline $ confirmedTransactionWizard es)
+  mt <- runInputT (setComplete noCompletion defaultSettings) (System.Console.Wizard.run $ haskeline $ confirmedTransactionWizard es)
   case mt of
     Nothing -> fail "urk ?"
     Just t -> do
diff --git a/Hledger/Cli/Commands/Balance.hs b/Hledger/Cli/Commands/Balance.hs
--- a/Hledger/Cli/Commands/Balance.hs
+++ b/Hledger/Cli/Commands/Balance.hs
@@ -247,10 +247,9 @@
  ,multiBalanceReportHtmlRows
  ,balanceReportAsTable
  ,balanceReportTableAsText
- ,tests_Hledger_Cli_Commands_Balance
+ ,tests_Balance
 ) where
 
-import Control.Monad (when)
 import Data.List
 import Data.Maybe
 --import qualified Data.Map as Map
@@ -258,8 +257,6 @@
 import qualified Data.Text.Lazy as TL
 import System.Console.CmdArgs.Explicit as C
 import Lucid as L
-import Text.CSV
-import Test.HUnit
 import Text.Printf (printf)
 import Text.Tabular as T
 --import Text.Tabular.AsciiWide
@@ -267,6 +264,7 @@
 import Hledger
 import Hledger.Cli.CliOptions
 import Hledger.Cli.Utils
+import Hledger.Read.CsvReader (CSV, printCSV)
 
 
 -- | Command line options for this command.
@@ -314,7 +312,6 @@
       case (budget, interval) of
         (True, _) -> do
           -- single or multicolumn budget report
-          when (sort_amount_ ropts) $ error' "Sorry, --sort-amount is not yet supported with --budget."  -- TODO
           reportspan <- reportSpan j ropts
           let budgetreport     = dbg1 "budgetreport"     $ budgetReport ropts assrt showunbudgeted reportspan d j
                 where
@@ -395,21 +392,6 @@
                 in overline : totallines
                Left _ -> []
 
-tests_balanceReportAsText = [
-  "balanceReportAsText" ~: do
-  -- "unicode in balance layout" ~: do
-    j <- readJournal'
-      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"
-    let opts = defreportopts
-    balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is`
-      unlines
-      ["                -100  актив:наличные"
-      ,"                 100  расходы:покупки"
-      ,"--------------------"
-      ,"                   0"
-      ]
- ]
-
 {-
 :r
 This implementation turned out to be a bit convoluted but implements the following algorithm for formatting:
@@ -646,5 +628,19 @@
             | otherwise    =  showMixedAmountOneLineWithoutPrice
 
 
-tests_Hledger_Cli_Commands_Balance = TestList
-  tests_balanceReportAsText
+tests_Balance = tests "Balance" [
+
+   tests "balanceReportAsText" [
+    test "unicode in balance layout" $ do
+      j <- io $ readJournal' "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"
+      let opts = defreportopts
+      balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is`
+        unlines
+        ["                -100  актив:наличные"
+        ,"                 100  расходы:покупки"
+        ,"--------------------"
+        ,"                   0"
+        ]
+  ]
+
+ ]
diff --git a/Hledger/Cli/Commands/Balancesheet.hs b/Hledger/Cli/Commands/Balancesheet.hs
--- a/Hledger/Cli/Commands/Balancesheet.hs
+++ b/Hledger/Cli/Commands/Balancesheet.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}
+{-# LANGUAGE QuasiQuotes, RecordWildCards #-}
 {-|
 
 The @balancesheet@ command prints a simple balance sheet.
@@ -8,12 +8,10 @@
 module Hledger.Cli.Commands.Balancesheet (
   balancesheetmode
  ,balancesheet
- ,tests_Hledger_Cli_Commands_Balancesheet
 ) where
 
 import Data.String.Here
 import System.Console.CmdArgs.Explicit
-import Test.HUnit
 
 import Hledger
 import Hledger.Cli.CliOptions
@@ -56,7 +54,3 @@
 balancesheet :: CliOpts -> Journal -> IO ()
 balancesheet = compoundBalanceCommand balancesheetSpec
 
-tests_Hledger_Cli_Commands_Balancesheet :: Test
-tests_Hledger_Cli_Commands_Balancesheet = TestList
- [
- ]
diff --git a/Hledger/Cli/Commands/Balancesheetequity.hs b/Hledger/Cli/Commands/Balancesheetequity.hs
--- a/Hledger/Cli/Commands/Balancesheetequity.hs
+++ b/Hledger/Cli/Commands/Balancesheetequity.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}
+{-# LANGUAGE QuasiQuotes, RecordWildCards #-}
 {-|
 
 The @balancesheetequity@ command prints a simple balance sheet.
diff --git a/Hledger/Cli/Commands/Cashflow.hs b/Hledger/Cli/Commands/Cashflow.hs
--- a/Hledger/Cli/Commands/Cashflow.hs
+++ b/Hledger/Cli/Commands/Cashflow.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}
+{-# LANGUAGE QuasiQuotes, RecordWildCards #-}
 {-|
 
 The @cashflow@ command prints a simplified cashflow statement.  It just
@@ -11,12 +11,10 @@
 module Hledger.Cli.Commands.Cashflow (
   cashflowmode
  ,cashflow
- ,tests_Hledger_Cli_Commands_Cashflow
 ) where
 
 import Data.String.Here
 import System.Console.CmdArgs.Explicit
-import Test.HUnit
 
 import Hledger
 import Hledger.Cli.CliOptions
@@ -52,8 +50,3 @@
 
 cashflow :: CliOpts -> Journal -> IO ()
 cashflow = compoundBalanceCommand cashflowSpec
-
-tests_Hledger_Cli_Commands_Cashflow :: Test
-tests_Hledger_Cli_Commands_Cashflow = TestList
- [
- ]
diff --git a/Hledger/Cli/Commands/Checkdates.hs b/Hledger/Cli/Commands/Checkdates.hs
--- a/Hledger/Cli/Commands/Checkdates.hs
+++ b/Hledger/Cli/Commands/Checkdates.hs
@@ -1,16 +1,15 @@
 {-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE NoOverloadedStrings #-} -- prevent trouble if turned on in ghci
 
 module Hledger.Cli.Commands.Checkdates (
   checkdatesmode
  ,checkdates
- ,tests_Hledger_Cli_Commands_Checkdates
 ) where
 
 import Data.String.Here
 import Hledger
 import Hledger.Cli.CliOptions
 import System.Console.CmdArgs.Explicit
-import Test.HUnit
 import Text.Printf
 
 -- checkdatesmode :: Mode RawOpts
@@ -78,8 +77,3 @@
       if compare previous current
       then acc{fa_previous=Just current}
       else acc{fa_error=Just current}
-
-tests_Hledger_Cli_Commands_Checkdates :: Test
-tests_Hledger_Cli_Commands_Checkdates = TestList
- [
- ]
diff --git a/Hledger/Cli/Commands/Close.hs b/Hledger/Cli/Commands/Close.hs
--- a/Hledger/Cli/Commands/Close.hs
+++ b/Hledger/Cli/Commands/Close.hs
@@ -7,11 +7,13 @@
 ) 
 where
 
+import Control.Monad (when)
 import Data.Maybe
 import Data.String.Here
 import Data.Time.Calendar
 import Hledger
 import Hledger.Cli.CliOptions
+import System.Console.CmdArgs.Explicit as C
 
 closemode = hledgerCommandMode
   [here| close equity
@@ -40,6 +42,9 @@
 To close on some other date, use: `hledger close -e OPENINGDATE ...`.
 (-p or date: can also be used, the begin date is ignored.)
 
+You can chose to print just one of the transactions with `--opening` 
+or `--closing`.
+
 For example, carrying asset/liability balances into a new file for 2018:
 ```
 $ hledger close -f 2017.journal -e 2018/1/1 ^assets ^liab >>2017.journal
@@ -58,14 +63,20 @@
     assets:bank:checking  -1  ; date:2018/1/1
 ```
   |]
-  []
+  [flagNone ["opening"] (\opts -> setboolopt "opening" opts) "show just opening transaction"
+  ,flagNone ["closing"] (\opts -> setboolopt "closing" opts) "show just closing transaction"
+  ]
   [generalflagsgroup1]
   []
   ([], Just $ argsFlag "[QUERY]")
 
-close CliOpts{reportopts_=ropts} j = do
+close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
   today <- getCurrentDay
   let 
+      (opening, closing) = 
+        case (boolopt "opening" rawopts, boolopt "closing" rawopts) of
+          (False, False) -> (True, True) -- by default show both opening and closing
+          (o, c) -> (o, c)
       ropts_ = ropts{balancetype_=HistoricalBalance, accountlistmode_=ALFlat}
       q = queryFromOpts today ropts_
       openingdate = fromMaybe today $ queryEndDate False q
@@ -88,5 +99,6 @@
             ,b <- amounts $ normaliseMixedAmountSquashPricesForDisplay mb
             ]
            ++ [posting{paccount="equity:closing balances", pamount=negate balancingamt}]
-  putStr $ showTransaction (nulltransaction{tdate=closingdate, tdescription="closing balances", tpostings=nps})
-  putStr $ showTransaction (nulltransaction{tdate=openingdate, tdescription="opening balances", tpostings=ps})
+  when closing $ putStr $ showTransaction (nulltransaction{tdate=closingdate, tdescription="closing balances", tpostings=nps})
+  when opening $ putStr $ showTransaction (nulltransaction{tdate=openingdate, tdescription="opening balances", tpostings=ps})
+
diff --git a/Hledger/Cli/Commands/Files.hs b/Hledger/Cli/Commands/Files.hs
new file mode 100644
--- /dev/null
+++ b/Hledger/Cli/Commands/Files.hs
@@ -0,0 +1,48 @@
+{-|
+
+The @files@ command lists included files.
+
+-}
+
+{-# LANGUAGE OverloadedStrings #-}
+
+module Hledger.Cli.Commands.Files (
+  filesmode
+ ,files
+) where
+
+import Data.List
+-- import Data.Text (Text)
+import Safe
+import System.Console.CmdArgs.Explicit as C
+
+import Hledger
+import Prelude hiding (putStrLn)
+import Hledger.Utils.UTF8IOCompat (putStrLn)
+import Hledger.Cli.CliOptions
+
+
+-- | Command line options for this command.
+filesmode = (defCommandMode $ ["files"] ) {
+  modeHelp = "show names of included files" 
+ ,modeHelpSuffix = [
+     "This command lists names of all files included in the parsed journal(s)." 
+    ,"With REGEX argument will list only files matching regular expression (case sensitive)."
+   ]
+ ,modeGroupFlags = C.Group {
+     groupUnnamed = []
+    ,groupHidden = []
+    ,groupNamed = [generalflagsgroup2]
+    }
+ ,modeArgs=  ([], Just $ argsFlag "[REGEX]")
+ }
+
+-- | The files command.
+files :: CliOpts -> Journal -> IO ()
+files CliOpts{rawopts_=rawopts} j = do
+  let args = listofstringopt "args" rawopts
+      regex = headMay args
+      files = (maybe id (filter . regexMatches) regex) 
+              $ map fst 
+              $ jfiles j
+  mapM_ putStrLn files
diff --git a/Hledger/Cli/Commands/Incomestatement.hs b/Hledger/Cli/Commands/Incomestatement.hs
--- a/Hledger/Cli/Commands/Incomestatement.hs
+++ b/Hledger/Cli/Commands/Incomestatement.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings, NoCPP #-}
+{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings #-}
 {-|
 
 The @incomestatement@ command prints a simple income statement (profit & loss report).
@@ -8,12 +8,10 @@
 module Hledger.Cli.Commands.Incomestatement (
   incomestatementmode
  ,incomestatement
- ,tests_Hledger_Cli_Commands_Incomestatement
 ) where
 
 import Data.String.Here
 import System.Console.CmdArgs.Explicit
-import Test.HUnit
 
 import Hledger
 import Hledger.Cli.CliOptions
@@ -55,8 +53,3 @@
 
 incomestatement :: CliOpts -> Journal -> IO ()
 incomestatement = compoundBalanceCommand incomestatementSpec
-
-tests_Hledger_Cli_Commands_Incomestatement :: Test
-tests_Hledger_Cli_Commands_Incomestatement = TestList
- [
- ]
diff --git a/Hledger/Cli/Commands/Prices.hs b/Hledger/Cli/Commands/Prices.hs
--- a/Hledger/Cli/Commands/Prices.hs
+++ b/Hledger/Cli/Commands/Prices.hs
@@ -17,28 +17,34 @@
 
 pricesmode = hledgerCommandMode
   [here| prices
-Print all market prices from the journal.
+Print market price directives from the journal.
+With --costs, also print synthetic market prices based on transaction prices.
+With --inverted-costs, also print inverse prices based on transaction prices.
+Prices (and postings providing prices) can be filtered by a query.
   |]
   [flagNone ["costs"] (setboolopt "costs") "print transaction prices from postings"
   ,flagNone ["inverted-costs"] (setboolopt "inverted-costs") "print transaction inverted prices from postings also"]
   [generalflagsgroup1]
   []
-  ([], Nothing)
+  ([], Just $ argsFlag "[QUERY]")
 
+-- XXX the original hledger-prices script always ignored assertions 
 prices opts j = do
-  -- XXX the original hledger-prices script always ignored assertions 
-  let cprices = concatMap postingCosts . allPostings $ j
-      icprices = concatMap postingCosts . mapAmount invertPrice . allPostings $ j
-      printPrices = mapM_ (putStrLn . showPrice)
-      forBoolOpt opt | boolopt opt $ rawopts_ opts = id
-                     | otherwise = const []
-      allPrices = sortOn mpdate . concat $
-          [ jmarketprices j
-          , forBoolOpt "costs" cprices
-          , forBoolOpt "inverted-costs" icprices
-          ]
-  
-  printPrices allPrices
+  d <- getCurrentDay
+  let
+    q          = queryFromOpts d (reportopts_ opts)
+    ps         = filter (matchesPosting q) $ allPostings j
+    mprices    = jmarketprices j
+    cprices    = concatMap postingCosts ps
+    icprices   = concatMap postingCosts . mapAmount invertPrice $ ps
+    allprices  = mprices ++ ifBoolOpt "costs" cprices ++ ifBoolOpt "inverted-costs" icprices
+  mapM_ (putStrLn . showPrice) $
+    sortOn mpdate $
+    filter (matchesMarketPrice q) $
+    allprices
+  where
+    ifBoolOpt opt | boolopt opt $ rawopts_ opts = id
+                  | otherwise = const []
 
 showPrice :: MarketPrice -> String
 showPrice mp = unwords ["P", show $ mpdate mp, T.unpack . quoteCommoditySymbolIfNeeded $ mpcommodity mp, showAmountWithZeroCommodity $ mpamount mp]
diff --git a/Hledger/Cli/Commands/Print.hs b/Hledger/Cli/Commands/Print.hs
--- a/Hledger/Cli/Commands/Print.hs
+++ b/Hledger/Cli/Commands/Print.hs
@@ -11,15 +11,13 @@
  ,print'
  -- ,entriesReportAsText
  ,originalTransaction
- ,tests_Hledger_Cli_Commands_Print
 )
 where
 
 import Data.Text (Text)
 import qualified Data.Text as T
 import System.Console.CmdArgs.Explicit
-import Test.HUnit
-import Text.CSV
+import Hledger.Read.CsvReader (CSV, printCSV)
 
 import Hledger
 import Hledger.Cli.CliOptions
@@ -181,8 +179,3 @@
       | otherwise           = Just $ snd $ head historymatches
       where
         historymatches = transactionsSimilarTo j q desc
-
--- tests
-
-tests_Hledger_Cli_Commands_Print = TestList []
-  -- tests_showTransactions
diff --git a/Hledger/Cli/Commands/Register.hs b/Hledger/Cli/Commands/Register.hs
--- a/Hledger/Cli/Commands/Register.hs
+++ b/Hledger/Cli/Commands/Register.hs
@@ -12,7 +12,7 @@
  ,postingsReportAsText
  ,postingsReportItemAsText
  -- ,showPostingWithBalanceForVty
- ,tests_Hledger_Cli_Commands_Register
+ ,tests_Register
 ) where
 
 import Data.List
@@ -20,14 +20,12 @@
 -- import Data.Text (Text)
 import qualified Data.Text as T
 import System.Console.CmdArgs.Explicit
-import Text.CSV
-import Test.HUnit
+import Hledger.Read.CsvReader (CSV, Record, printCSV)
 
 import Hledger
 import Hledger.Cli.CliOptions
 import Hledger.Cli.Utils
 
-
 registermode = (defCommandMode $ ["register"] ++ aliases) {
   modeHelp = "show postings and running total. With --date2, show and sort by secondary date instead." `withAliases` aliases
  ,modeGroupFlags = Group {
@@ -97,17 +95,6 @@
     itemamt (_,_,_,Posting{pamount=a},_) = a
     itembal (_,_,_,_,a) = a
 
-tests_postingsReportAsText = [
-  "postingsReportAsText" ~: do
-  -- "unicode in register layout" ~: do
-    j <- readJournal'
-      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"
-    let opts = defreportopts
-    (postingsReportAsText defcliopts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines
-      ["2009/01/01 медвежья шкура       расходы:покупки                100           100"
-      ,"                                актив:наличные                -100             0"]
- ]
-
 -- | Render one register report line item as plain text. Layout is like so:
 -- @
 -- <---------------- width (specified, terminal width, or 80) -------------------->
@@ -201,6 +188,17 @@
       (balfirstline:balrest) = take numlines $ replicate (numlines - ballen) "" ++ ballines -- balance amount is bottom-aligned
       spacer = replicate (totalwidth - (amtwidth + 2 + balwidth)) ' '
 
-tests_Hledger_Cli_Commands_Register :: Test
-tests_Hledger_Cli_Commands_Register = TestList
-  tests_postingsReportAsText
+-- tests
+
+tests_Register = tests "Register" [
+
+   tests "postingsReportAsText" [
+    test "unicode in register layout" $ do
+      j <- io $ readJournal' "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"
+      let opts = defreportopts
+      (postingsReportAsText defcliopts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines
+        ["2009/01/01 медвежья шкура       расходы:покупки                100           100"
+        ,"                                актив:наличные                -100             0"]
+   ]
+
+ ]
diff --git a/Hledger/Cli/Commands/Rewrite.hs b/Hledger/Cli/Commands/Rewrite.hs
--- a/Hledger/Cli/Commands/Rewrite.hs
+++ b/Hledger/Cli/Commands/Rewrite.hs
@@ -10,6 +10,7 @@
 #if !(MIN_VERSION_base(4,11,0))
 import Control.Monad.Writer
 #endif
+import Data.Functor.Identity
 import Data.List (sortOn, foldl')
 import Data.String.Here
 import qualified Data.Text as T
@@ -23,7 +24,8 @@
 
 rewritemode = hledgerCommandMode
   [here| rewrite
-Print all transactions, adding custom postings to the matched ones.
+Print all transactions, rewriting the postings of matched transactions.
+For now the only rewrite available is adding new postings, like print --auto.
 
 FLAGS
 
@@ -146,6 +148,20 @@
 
 https://github.com/simonmichael/hledger/issues/99
 
+#### rewrite vs. print --auto
+
+This command predates print --auto, and currently does much the same thing,
+but with these differences:
+
+- with multiple files, rewrite lets rules in any file affect all other files.
+  print --auto uses standard directive scoping; rules affect only child files.
+
+- rewrite's query limits which transactions can be rewritten; all are printed.
+  print --auto's query limits which transactions are printed.
+
+- rewrite applies rules specified on command line or in the journal.
+  print --auto applies rules specified in the journal.
+
   |]
   [flagReq ["add-posting"] (\s opts -> Right $ setopt "add-posting" s opts) "'ACCT  AMTEXPR'"
            "add a posting to ACCT, which may be parenthesised. AMTEXPR is either a literal amount, or *N which means the transaction's first matched amount multiplied by N (a decimal number). Two spaces separate ACCT and AMTEXPR."
@@ -161,33 +177,29 @@
 -- TODO allow using this on unbalanced entries, eg to rewrite while editing
 
 rewrite opts@CliOpts{rawopts_=rawopts,reportopts_=ropts} j@Journal{jtxns=ts} = do 
-  d <- getCurrentDay
-  let q = queryFromOpts d ropts
-  modifier <- modifierTransactionFromOpts rawopts
   -- create re-writer
-  let modifiers = modifier : jmodifiertxns j
-      -- Note that some query matches require transaction. Thus modifiers
-      -- pipeline should include txnTieKnot on every step.
-      modifier' = foldr (flip (.) . fmap txnTieKnot . runModifierTransaction q) id modifiers
+  let modifiers = transactionModifierFromOpts opts : jtxnmodifiers j
+      applyallmodifiers = foldr (flip (.) . transactionModifierToFunction) id modifiers
   -- rewrite matched transactions
-  let j' = j{jtxns=map modifier' ts}
-  -- run the print command, showing all transactions
-  outputFromOpts rawopts opts{reportopts_=ropts{query_=""}} j j'
-
-postingp' :: T.Text -> IO Posting
-postingp' t = runJournalParser (postingp Nothing <* eof) t' >>= \case
-        Left err -> fail $ parseErrorPretty' t' err
-        Right p -> return p
-    where t' = " " <> t <> "\n" -- inject space and newline for proper parsing
+  let j' = j{jtxns=map applyallmodifiers ts}
+  -- run the print command, showing all transactions, or show diffs
+  printOrDiff rawopts opts{reportopts_=ropts{query_=""}} j j'
 
-modifierTransactionFromOpts :: RawOpts -> IO ModifierTransaction
-modifierTransactionFromOpts opts = do
-    postings <- mapM (postingp' . stripquotes . T.pack) $ listofstringopt "add-posting" opts
-    return
-        ModifierTransaction { mtvalueexpr = T.empty, mtpostings = postings }
+-- | Build a 'TransactionModifier' from any query arguments and --add-posting flags
+-- provided on the command line, or throw a parse error.
+transactionModifierFromOpts :: CliOpts -> TransactionModifier
+transactionModifierFromOpts CliOpts{rawopts_=rawopts,reportopts_=ropts} = 
+  TransactionModifier{tmquerytxt=q, tmpostings=ps}
+  where
+    q = T.pack $ query_ ropts
+    ps = map (parseposting . stripquotes . T.pack) $ listofstringopt "add-posting" rawopts
+    parseposting t = either (error' . parseErrorPretty' t') id ep 
+      where
+        ep = runIdentity (runJournalParser (postingp Nothing <* eof) t')
+        t' = " " <> t <> "\n" -- inject space and newline for proper parsing
 
-outputFromOpts :: RawOpts -> (CliOpts -> Journal -> Journal -> IO ())
-outputFromOpts opts
+printOrDiff :: RawOpts -> (CliOpts -> Journal -> Journal -> IO ())
+printOrDiff opts
     | boolopt "diff" opts = const diffOutput
     | otherwise = flip (const print')
 
@@ -198,8 +210,7 @@
 
 type Chunk = (GenericSourcePos, [DiffLine String])
 
--- | Render list of changed lines as a unified diff
---
+-- XXX doctests, update needed:
 -- >>> putStr $ renderPatch [(GenericSourcePos "a" 1 1, [D.First "x", D.Second "y"])]
 -- --- a
 -- +++ a
@@ -224,6 +235,7 @@
 -- +++ b
 -- @@ -5,0 +5,1 @@
 -- +z
+-- | Render list of changed lines as a unified diff
 renderPatch :: [Chunk] -> String
 renderPatch = go Nothing . sortOn fst where
     go _ [] = ""
diff --git a/Hledger/Cli/Commands/Roi.hs b/Hledger/Cli/Commands/Roi.hs
new file mode 100644
--- /dev/null
+++ b/Hledger/Cli/Commands/Roi.hs
@@ -0,0 +1,244 @@
+{-# LANGUAGE QuasiQuotes,ParallelListComp #-}
+{-|
+
+The @roi@ command prints internal rate of return and time-weighted rate of return for and investment.
+
+-}
+
+module Hledger.Cli.Commands.Roi ( 
+  roimode
+  , roi
+) where
+
+import Control.Monad
+import System.Exit
+import Data.Time.Calendar
+import Text.Printf
+import Data.Function (on)
+import Data.List
+import Data.Ord
+import Statistics.Math.RootFinding
+import Data.Decimal
+import Data.String.Here
+import System.Console.CmdArgs.Explicit as CmdArgs
+
+import Text.Tabular as Tbl
+import Text.Tabular.AsciiWide as Ascii
+
+import Hledger
+import Hledger.Cli.CliOptions
+
+
+roimode = (defCommandMode $ ["roi"]) {
+  modeHelp = "shows return on investment for your portfolio."
+  ,modeHelpSuffix=lines [here|
+This command will show you time-weighted (TWR) and money-weighted (IRR) rate of return on your investments.
+
+Command assumes that you have account(s) that hold nothing but your investments and whenever you record current appraisal/valuation of these investments you offset unrealized profit and loss into account(s) that, again, hold nothing but unrealized profit and loss.
+
+Any transactions affecting balance of investment account(s) and not originating from unrealized profit and loss account(s) are assumed to be your investments or withdrawals.
+
+At a minimum, you need to supply query (which could be just an account name) to select your investments with `--inv`, and another query to identify your profit and loss transactions with `--pnl`.
+
+Command will compute and display internalized rate of return (IRR) and time-weighted rate of return (TWR) for your investments for the time period requested. Both rates of return are annualized before display, regardless of the length of reporting interval.
+|]
+  ,modeGroupFlags = CmdArgs.Group {
+    groupUnnamed = [
+       flagNone ["cashflow"] (setboolopt "cashflow") "show all amounts that were used to compute returns"
+       , flagReq ["investment"] (\s opts -> Right $ setopt "investment" s opts) "QUERY"
+         "query to select your investment transactions"
+       , flagReq ["profit-loss","pnl"] (\s opts -> Right $ setopt "pnl" s opts) "QUERY"
+         "query to select profit-and-loss or appreciation/valuation transactions"
+       ]
+    , groupHidden = []
+    ,groupNamed = [generalflagsgroup1]
+    }
+  }
+
+-- One reporting span, 
+data OneSpan = OneSpan 
+  Day -- start date, inclusive
+  Day   -- end date, exclusive
+  Quantity -- value of investment at the beginning of day on spanBegin_
+  Quantity  -- value of investment at the end of day on spanEnd_
+  [(Day,Quantity)] -- all deposits and withdrawals (but not changes of value) in the DateSpan [spanBegin_,spanEnd_)
+ deriving (Show)
+  
+
+roi ::  CliOpts -> Journal -> IO ()
+roi CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
+  d <- getCurrentDay
+  let 
+    investmentsQuery = queryFromOpts d $ ropts{query_ = stringopt "investment" rawopts,period_=PeriodAll}
+    pnlQuery         = queryFromOpts d $ ropts{query_ = stringopt "pnl" rawopts,period_=PeriodAll}
+    showCashFlow      = boolopt "cashflow" rawopts
+    prettyTables     = pretty_tables_ ropts
+    
+    trans = dbg3 "investments" $ jtxns $ filterJournalTransactions investmentsQuery j
+  
+    journalSpan = 
+        let dates = map transactionDate2 trans in 
+        DateSpan (Just $ minimum dates) (Just $ addDays 1 $ maximum dates)            
+        
+    requestedSpan = periodAsDateSpan $ period_ ropts
+    requestedInterval = interval_ ropts
+    
+    wholeSpan = spanDefaultsFrom requestedSpan journalSpan 
+
+  when (null trans) $ do
+    putStrLn "No relevant transactions found. Check your investments query"
+    exitFailure
+  
+  let spans = case requestedInterval of
+        NoInterval -> [wholeSpan]
+        interval ->
+            splitSpan interval $
+            spanIntersect journalSpan wholeSpan
+
+  tableBody <- (flip mapM) spans $ \(DateSpan (Just spanBegin) (Just spanEnd)) -> do
+    -- Spans are [spanBegin,spanEnd), and spanEnd is 1 day after then actual end date we are interested in
+    let 
+      valueBefore =
+        total trans (And [ investmentsQuery
+                         , Date (DateSpan Nothing (Just spanBegin))])
+    
+      valueAfter  = 
+        total trans (And [investmentsQuery
+                         , Date (DateSpan Nothing (Just spanEnd))])
+        
+      cashFlow = 
+        calculateCashFlow trans (And [ Not investmentsQuery
+                                     , Not pnlQuery
+                                     , Date (DateSpan (Just spanBegin) (Just spanEnd)) ] )
+      
+      thisSpan = dbg3 "processing span" $ 
+                 OneSpan spanBegin spanEnd valueBefore valueAfter cashFlow
+      
+    irr <- internalRateOfReturn showCashFlow prettyTables thisSpan
+    twr <- timeWeightedReturn showCashFlow prettyTables investmentsQuery trans thisSpan
+    let cashFlowAmt = negate $ sum $ map snd cashFlow
+    return [ showDate spanBegin
+           , showDate (addDays (-1) spanEnd)
+           , show valueBefore
+           , show cashFlowAmt
+           , show valueAfter
+           , show (valueAfter - (valueBefore + cashFlowAmt))
+           , printf "%0.2f%%" irr
+           , printf "%0.2f%%" twr ]
+
+  let table = Table 
+              (Tbl.Group NoLine (map (Header . show) (take (length tableBody) [1..]))) 
+              (Tbl.Group DoubleLine 
+               [ Tbl.Group SingleLine [Header "Begin", Header "End"]
+               , Tbl.Group SingleLine [Header "Value (begin)", Header "Cashflow", Header "Value (end)", Header "PnL"]
+               , Tbl.Group SingleLine [Header "IRR", Header "TWR"]])
+              tableBody
+  
+  putStrLn $ Ascii.render prettyTables id id id table
+
+timeWeightedReturn showCashFlow prettyTables investmentsQuery trans (OneSpan spanBegin spanEnd valueBefore valueAfter cashFlow) = do
+  let initialUnitPrice = 100
+  let initialUnits = valueBefore / initialUnitPrice
+  let cashflow = 
+        -- Aggregate all entries for a single day, assuming that intraday interest is negligible
+        map (\date_cash -> let (dates, cash) = unzip date_cash in (head dates, sum cash))
+        $ groupBy ((==) `on` fst)
+        $ sortBy (comparing fst) 
+        $ map (\(d,a) -> (d, negate a)) 
+        $ filter ((/=0).snd) cashFlow
+    
+  let units = 
+        tail $
+        (flip scanl) 
+        (0,0,0,initialUnits)
+        (\(_,_,_,unitBalance) (date, amt) -> 
+          let valueOnDate = 
+                total trans (And [investmentsQuery, Date (DateSpan Nothing (Just date))])
+              unitPrice = if unitBalance == 0.0 then initialUnitPrice else valueOnDate / unitBalance
+              unitsBoughtOrSold = amt / unitPrice
+          in
+           (valueOnDate, unitsBoughtOrSold, unitPrice, unitBalance + unitsBoughtOrSold)
+        )  
+        cashflow
+  
+  let finalUnitBalance = if null units then initialUnits else let (_,_,_,u) = last units in u
+      finalUnitPrice = valueAfter / finalUnitBalance
+      totalTWR = roundTo 2 $ (finalUnitPrice - initialUnitPrice)
+      years = (fromIntegral $ diffDays spanEnd spanBegin)/365 :: Double
+      annualizedTWR = 100*((1+(realToFrac totalTWR/100))**(1/years)-1) :: Double
+        
+  let s d = show $ roundTo 2 d 
+  when showCashFlow $ do
+    printf "\nTWR cash flow for %s - %s\n" (showDate spanBegin) (showDate (addDays (-1) spanEnd))
+    let (dates', amounts') = unzip cashflow
+        (valuesOnDate',unitsBoughtOrSold', unitPrices', unitBalances') = unzip4 units
+        add x lst = if valueBefore/=0 then x:lst else lst
+        dates = add spanBegin dates'
+        amounts = add valueBefore amounts'
+        unitsBoughtOrSold = add initialUnits unitsBoughtOrSold'
+        unitPrices = add initialUnitPrice unitPrices'
+        unitBalances = add initialUnits unitBalances'
+        valuesOnDate = add 0 valuesOnDate'
+        
+    putStr $ Ascii.render prettyTables id id id 
+      (Table 
+       (Tbl.Group NoLine (map (Header . showDate) dates))
+       (Tbl.Group DoubleLine [ Tbl.Group SingleLine [Header "Portfolio value", Header "Unit balance"] 
+                         , Tbl.Group SingleLine [Header "Cash", Header "Unit price", Header "Units"]
+                         , Tbl.Group SingleLine [Header "New Unit Balance"]])
+       [ [value, oldBalance, amt, prc, udelta, balance] 
+       | value <- map s valuesOnDate
+       | oldBalance <- map s (0:unitBalances)
+       | balance <- map s unitBalances
+       | amt <- map s amounts
+       | prc <- map s unitPrices
+       | udelta <- map s unitsBoughtOrSold ])
+  
+    printf "Final unit price: %s/%s=%s U.\nTotal TWR: %s%%.\nPeriod: %.2f years.\nAnnualized TWR: %.2f%%\n\n" (s valueAfter) (s finalUnitBalance) (s finalUnitPrice) (s totalTWR) years annualizedTWR
+  
+  return annualizedTWR
+  
+
+internalRateOfReturn showCashFlow prettyTables (OneSpan spanBegin spanEnd valueBefore valueAfter cashFlow) = do 
+  let prefix = (spanBegin, negate valueBefore)
+
+      postfix = (spanEnd, valueAfter)
+
+      totalCF = filter ((/=0) . snd) $ prefix : (sortBy (comparing fst) cashFlow) ++ [postfix]
+
+  when showCashFlow $ do
+    printf "\nIRR cash flow for %s - %s\n" (showDate spanBegin) (showDate (addDays (-1) spanEnd)) 
+    let (dates, amounts) = unzip totalCF
+    putStrLn $ Ascii.render prettyTables id id id 
+      (Table 
+       (Tbl.Group NoLine (map (Header . showDate) dates))
+       (Tbl.Group SingleLine [Header "Amount"])
+       (map ((:[]) . show) amounts))
+                             
+  -- 0% is always a solution, so require at least something here
+  case ridders 0.00001 (0.000000000001,10000) (interestSum spanEnd totalCF) of
+    Root rate -> return ((rate-1)*100)
+    NotBracketed -> error "Error: No solution -- not bracketed."
+    SearchFailed -> error "Error: Failed to find solution."
+
+type CashFlow = [(Day, Quantity)]
+
+interestSum :: Day -> CashFlow -> Double -> Double
+interestSum referenceDay cf rate = sum $ map go cf
+    where go (t,m) = (fromRational $ toRational m) * (rate ** (fromIntegral (referenceDay `diffDays` t) / 365))
+
+
+calculateCashFlow :: [Transaction] -> Query -> CashFlow
+calculateCashFlow trans query = map go trans
+    where
+    go t = (transactionDate2 t, total [t] query)
+
+total :: [Transaction] -> Query -> Quantity
+total trans query = unMix $ sumPostings $ filter (matchesPosting query) $ concatMap realPostings trans
+    
+unMix :: MixedAmount -> Quantity   
+unMix a = 
+  case (normaliseMixedAmount $ costOfMixedAmount a) of
+    (Mixed [a]) -> aquantity a
+    _ -> error "MixedAmount failed to normalize"
+
diff --git a/Hledger/Cli/CompoundBalanceCommand.hs b/Hledger/Cli/CompoundBalanceCommand.hs
--- a/Hledger/Cli/CompoundBalanceCommand.hs
+++ b/Hledger/Cli/CompoundBalanceCommand.hs
@@ -18,7 +18,7 @@
 import qualified Data.Text as TS
 import qualified Data.Text.Lazy as TL
 import System.Console.CmdArgs.Explicit as C
-import Text.CSV
+import Hledger.Read.CsvReader (CSV, printCSV)
 import Lucid as L
 import Text.Tabular as T
 
diff --git a/Hledger/Cli/DocFiles.hs b/Hledger/Cli/DocFiles.hs
--- a/Hledger/Cli/DocFiles.hs
+++ b/Hledger/Cli/DocFiles.hs
@@ -22,6 +22,8 @@
 
 import Prelude ()
 import "base-compat-batteries" Prelude.Compat
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as BC
 import Data.FileEmbed
 import Data.String
 import System.IO
@@ -32,82 +34,82 @@
 
 type Topic = String
 
-docFiles :: IsString a => [(Topic, (a, a, a))]
+docFiles :: [(Topic, (ByteString, ByteString, ByteString))]
 docFiles = [
    ("hledger",
-    ($(makeRelativeToProject "embeddedfiles/hledger.1" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger.1" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger.info" >>= embedFile)
     ))
   ,("hledger-ui",
-    ($(makeRelativeToProject "embeddedfiles/hledger-ui.1" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-ui.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-ui.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger-ui.1" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-ui.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-ui.info" >>= embedFile)
     ))
   ,("hledger-web",
-    ($(makeRelativeToProject "embeddedfiles/hledger-web.1" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-web.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-web.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger-web.1" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-web.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-web.info" >>= embedFile)
     ))
   ,("hledger-api",
-    ($(makeRelativeToProject "embeddedfiles/hledger-api.1" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-api.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger-api.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger-api.1" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-api.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger-api.info" >>= embedFile)
     ))
   ,("journal",
-    ($(makeRelativeToProject "embeddedfiles/hledger_journal.5" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_journal.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_journal.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger_journal.5" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_journal.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_journal.info" >>= embedFile)
     ))
   ,("csv",
-    ($(makeRelativeToProject "embeddedfiles/hledger_csv.5" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_csv.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_csv.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger_csv.5" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_csv.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_csv.info" >>= embedFile)
     ))
   ,("timeclock",
-    ($(makeRelativeToProject "embeddedfiles/hledger_timeclock.5" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_timeclock.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_timeclock.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger_timeclock.5" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_timeclock.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_timeclock.info" >>= embedFile)
     ))
   ,("timedot",
-    ($(makeRelativeToProject "embeddedfiles/hledger_timedot.5" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_timedot.txt" >>= embedStringFile)
-    ,$(makeRelativeToProject "embeddedfiles/hledger_timedot.info" >>= embedStringFile)
+    ($(makeRelativeToProject "embeddedfiles/hledger_timedot.5" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_timedot.txt" >>= embedFile)
+    ,$(makeRelativeToProject "embeddedfiles/hledger_timedot.info" >>= embedFile)
     ))
   ]
 
 docTopics :: [Topic]
 docTopics = map fst docFiles
 
-lookupDocTxt :: IsString a => Topic -> a
+lookupDocTxt :: Topic -> ByteString
 lookupDocTxt name =
   maybe (fromString $ "No text manual found for topic: "++name) second3 $ lookup name docFiles
 
-lookupDocNroff :: IsString a => Topic -> a
+lookupDocNroff :: Topic -> ByteString
 lookupDocNroff name =
   maybe (fromString $ "No man page found for topic: "++name) first3 $ lookup name docFiles
 
-lookupDocInfo :: IsString a => Topic -> a
+lookupDocInfo :: Topic -> ByteString
 lookupDocInfo name =
   maybe (fromString $ "No info manual found for topic: "++name) third3 $ lookup name docFiles
 
 printHelpForTopic :: Topic -> IO ()
 printHelpForTopic t =
-  putStrLn $ lookupDocTxt t
+  BC.putStr (lookupDocTxt t)
 
 runPagerForTopic :: FilePath -> Topic -> IO ()
 runPagerForTopic exe t = do
   (Just inp, _, _, ph) <- createProcess (proc exe []){
     std_in=CreatePipe
     }
-  hPutStrLn inp (lookupDocTxt t)
+  BC.hPutStrLn inp (lookupDocTxt t)
   _ <- waitForProcess ph
   return ()
 
 runManForTopic :: Topic -> IO ()
 runManForTopic t =
   withSystemTempFile ("hledger-"++t++".nroff") $ \f h -> do
-    hPutStrLn h $ lookupDocNroff t
+    BC.hPutStrLn h $ lookupDocNroff t
     hClose h
      -- the temp file path will presumably have a slash in it, so man should read it
     callCommand $ "man " ++ f
@@ -115,7 +117,7 @@
 runInfoForTopic :: Topic -> IO ()
 runInfoForTopic t =
   withSystemTempFile ("hledger-"++t++".info") $ \f h -> do
-    hPutStrLn h $ lookupDocInfo t
+    BC.hPutStrLn h $ lookupDocInfo t
     hClose h
     callCommand $ "info " ++ f
 
diff --git a/Hledger/Cli/Main.hs b/Hledger/Cli/Main.hs
--- a/Hledger/Cli/Main.hs
+++ b/Hledger/Cli/Main.hs
@@ -115,7 +115,7 @@
     (argsbeforecmd, argsaftercmd') = break (==rawcmd) args
     argsaftercmd         = drop 1 argsaftercmd'
     dbgIO :: Show a => String -> a -> IO ()
-    dbgIO = tracePrettyAtIO 2
+    dbgIO = ptraceAtIO 2
 
   dbgIO "running" prognameandversion
   dbgIO "raw args" args
@@ -169,14 +169,17 @@
       | isBadCommand             = badCommandError
 
       -- builtin commands
-      | Just (cmdmode, cmdaction) <- findCommand cmd = do 
-        if cmd=="add" -- add command does extra work before reading journal
-        then (do
-          journalFilePathFromOpts opts >>= (ensureJournalFileExists . head) 
-          withJournalDo opts cmdaction)
-          `orShowHelp` cmdmode
-        else
-          withJournalDo opts cmdaction `orShowHelp` cmdmode
+      | Just (cmdmode, cmdaction) <- findCommand cmd =
+        (case cmd of
+          "test" -> -- should not read the journal
+            cmdaction opts (error "journal-less command tried to use the journal")
+          "add" ->  -- should create the journal if missing
+            (ensureJournalFileExists =<< (head <$> journalFilePathFromOpts opts)) >>
+            withJournalDo opts cmdaction
+          _ ->      -- all other commands: read the journal or fail if missing
+            withJournalDo opts cmdaction
+        )
+        `orShowHelp` cmdmode
 
       -- addon commands
       | isExternalCommand = do
@@ -225,16 +228,21 @@
        (bs,"--debug":[])                                   -> bs++"--debug=1":[]
        _                                                   -> as
 
-    -- -h ..., --version ...
-    moveArgs (f:a:as)   | isMovableNoArgFlag f                   = (moveArgs $ a:as) ++ [f]
-    -- -f FILE ..., --alias ALIAS ...
-    moveArgs (f:v:a:as) | isMovableReqArgFlag f, isValue v       = (moveArgs $ a:as) ++ [f,v]
-    -- -fFILE ..., --alias=ALIAS ...
-    moveArgs (fv:a:as)  | isMovableReqArgFlagAndValue fv         = (moveArgs $ a:as) ++ [fv]
-    -- -f(missing arg)
-    moveArgs (f:a:as)   | isMovableReqArgFlag f, not (isValue a) = (moveArgs $ a:as) ++ [f]
-    -- anything else
-    moveArgs as = as
+    moveArgs args = insertFlagsAfterCommand $ moveArgs' (args, [])
+      where
+        -- -h ..., --version ...
+        moveArgs' ((f:a:as), flags)   | isMovableNoArgFlag f                   = moveArgs' (a:as, flags ++ [f])
+        -- -f FILE ..., --alias ALIAS ...
+        moveArgs' ((f:v:a:as), flags) | isMovableReqArgFlag f, isValue v       = moveArgs' (a:as, flags ++ [f,v])
+        -- -fFILE ..., --alias=ALIAS ...
+        moveArgs' ((fv:a:as), flags)  | isMovableReqArgFlagAndValue fv         = moveArgs' (a:as, flags ++ [fv])
+        -- -f(missing arg)
+        moveArgs' ((f:a:as), flags)   | isMovableReqArgFlag f, not (isValue a) = moveArgs' (a:as, flags ++ [f])
+        -- anything else
+        moveArgs' (as, flags) = (as, flags)
+
+        insertFlagsAfterCommand ([],           flags) = flags
+        insertFlagsAfterCommand (command:args, flags) = [command] ++ flags ++ args
 
 isMovableNoArgFlag a  = "-" `isPrefixOf` a && dropWhile (=='-') a `elem` noargflagstomove
 
diff --git a/Hledger/Cli/Utils.hs b/Hledger/Cli/Utils.hs
--- a/Hledger/Cli/Utils.hs
+++ b/Hledger/Cli/Utils.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE ScopedTypeVariables, CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoOverloadedStrings #-} -- prevent trouble if turned on in ghci
 {-|
 
 Utilities for top-level modules and ghci. See also Hledger.Read and
@@ -13,7 +14,6 @@
      journalTransform,
      journalApplyValue,
      journalAddForecast,
-     generateAutomaticPostings,
      journalReload,
      journalReloadIfChanged,
      journalFileIsNewer,
@@ -25,7 +25,6 @@
      readFileStrictly,
      pivotByOpts,
      anonymiseByOpts,
-     Test(TestList),
     )
 where
 import Control.Exception as C
@@ -47,7 +46,6 @@
 import System.Info (os)
 import System.Process (readProcessWithExitCode)
 import System.Time (ClockTime, getClockTime, diffClockTimes, TimeDiff(TimeDiff))
-import Test.HUnit
 import Text.Printf
 import Text.Regex.TDFA ((=~))
 
diff --git a/embeddedfiles/hledger-api.1 b/embeddedfiles/hledger-api.1
--- a/embeddedfiles/hledger-api.1
+++ b/embeddedfiles/hledger-api.1
@@ -1,5 +1,5 @@
 
-.TH "hledger\-api" "1" "June 2018" "hledger\-api 1.9.99" "hledger User Manuals"
+.TH "hledger\-api" "1" "September 2018" "hledger\-api 1.10.99" "hledger User Manuals"
 
 
 
diff --git a/embeddedfiles/hledger-api.info b/embeddedfiles/hledger-api.info
--- a/embeddedfiles/hledger-api.info
+++ b/embeddedfiles/hledger-api.info
@@ -3,8 +3,8 @@
 
 File: hledger-api.info,  Node: Top,  Next: OPTIONS,  Up: (dir)
 
-hledger-api(1) hledger-api 1.9.99
-*********************************
+hledger-api(1) hledger-api 1.10.99
+**********************************
 
 hledger-api is a simple web API server, intended to support client-side
 web apps operating on hledger data.  It comes with a series of simple
@@ -80,7 +80,7 @@
 
 Tag Table:
 Node: Top72
-Node: OPTIONS1664
-Ref: #options1749
+Node: OPTIONS1666
+Ref: #options1751
 
 End Tag Table
diff --git a/embeddedfiles/hledger-api.txt b/embeddedfiles/hledger-api.txt
--- a/embeddedfiles/hledger-api.txt
+++ b/embeddedfiles/hledger-api.txt
@@ -117,4 +117,4 @@
 
 
 
-hledger-api 1.9.99                 June 2018                    hledger-api(1)
+hledger-api 1.10.99             September 2018                  hledger-api(1)
diff --git a/embeddedfiles/hledger-ui.1 b/embeddedfiles/hledger-ui.1
--- a/embeddedfiles/hledger-ui.1
+++ b/embeddedfiles/hledger-ui.1
@@ -1,5 +1,5 @@
 
-.TH "hledger\-ui" "1" "June 2018" "hledger\-ui 1.9.99" "hledger User Manuals"
+.TH "hledger\-ui" "1" "September 2018" "hledger\-ui 1.10.99" "hledger User Manuals"
 
 
 
@@ -75,6 +75,11 @@
 .TP
 .B \f[C]\-\-rules\-file=RULESFILE\f[]
 Conversion rules file to use when reading CSV (default: FILE.rules)
+.RS
+.RE
+.TP
+.B \f[C]\-\-separator=CHAR\f[]
+Field separator to expect when reading CSV (default: `,')
 .RS
 .RE
 .TP
diff --git a/embeddedfiles/hledger-ui.info b/embeddedfiles/hledger-ui.info
--- a/embeddedfiles/hledger-ui.info
+++ b/embeddedfiles/hledger-ui.info
@@ -3,8 +3,8 @@
 
 File: hledger-ui.info,  Node: Top,  Next: OPTIONS,  Up: (dir)
 
-hledger-ui(1) hledger-ui 1.9.99
-*******************************
+hledger-ui(1) hledger-ui 1.10.99
+********************************
 
 hledger-ui is hledger's curses-style interface, providing an efficient
 full-window text UI for viewing accounts and transactions, and some
@@ -61,6 +61,9 @@
 '--rules-file=RULESFILE'
 
      Conversion rules file to use when reading CSV (default: FILE.rules)
+'--separator=CHAR'
+
+     Field separator to expect when reading CSV (default: ',')
 '--alias=OLD=NEW'
 
      rename accounts named OLD to NEW
@@ -377,19 +380,19 @@
 
 Tag Table:
 Node: Top71
-Node: OPTIONS827
-Ref: #options924
-Node: KEYS4141
-Ref: #keys4236
-Node: SCREENS7195
-Ref: #screens7280
-Node: Accounts screen7370
-Ref: #accounts-screen7498
-Node: Register screen9728
-Ref: #register-screen9883
-Node: Transaction screen11957
-Ref: #transaction-screen12115
-Node: Error screen12985
-Ref: #error-screen13107
+Node: OPTIONS829
+Ref: #options926
+Node: KEYS4226
+Ref: #keys4321
+Node: SCREENS7280
+Ref: #screens7365
+Node: Accounts screen7455
+Ref: #accounts-screen7583
+Node: Register screen9813
+Ref: #register-screen9968
+Node: Transaction screen12042
+Ref: #transaction-screen12200
+Node: Error screen13070
+Ref: #error-screen13192
 
 End Tag Table
diff --git a/embeddedfiles/hledger-ui.txt b/embeddedfiles/hledger-ui.txt
--- a/embeddedfiles/hledger-ui.txt
+++ b/embeddedfiles/hledger-ui.txt
@@ -60,6 +60,9 @@
               Conversion  rules  file  to  use  when  reading  CSV   (default:
               FILE.rules)
 
+       --separator=CHAR
+              Field separator to expect when reading CSV (default: `,')
+
        --alias=OLD=NEW
               rename accounts named OLD to NEW
 
@@ -384,4 +387,4 @@
 
 
 
-hledger-ui 1.9.99                  June 2018                     hledger-ui(1)
+hledger-ui 1.10.99              September 2018                   hledger-ui(1)
diff --git a/embeddedfiles/hledger-web.1 b/embeddedfiles/hledger-web.1
--- a/embeddedfiles/hledger-web.1
+++ b/embeddedfiles/hledger-web.1
@@ -1,5 +1,5 @@
 
-.TH "hledger\-web" "1" "June 2018" "hledger\-web 1.9.99" "hledger User Manuals"
+.TH "hledger\-web" "1" "September 2018" "hledger\-web 1.10.99" "hledger User Manuals"
 
 
 
@@ -130,6 +130,11 @@
 .TP
 .B \f[C]\-\-rules\-file=RULESFILE\f[]
 Conversion rules file to use when reading CSV (default: FILE.rules)
+.RS
+.RE
+.TP
+.B \f[C]\-\-separator=CHAR\f[]
+Field separator to expect when reading CSV (default: `,')
 .RS
 .RE
 .TP
diff --git a/embeddedfiles/hledger-web.info b/embeddedfiles/hledger-web.info
--- a/embeddedfiles/hledger-web.info
+++ b/embeddedfiles/hledger-web.info
@@ -3,8 +3,8 @@
 
 File: hledger-web.info,  Node: Top,  Next: OPTIONS,  Up: (dir)
 
-hledger-web(1) hledger-web 1.9.99
-*********************************
+hledger-web(1) hledger-web 1.10.99
+**********************************
 
 hledger-web is hledger's web interface.  It starts a simple web
 application for browsing and adding transactions, and optionally opens
@@ -106,6 +106,9 @@
 '--rules-file=RULESFILE'
 
      Conversion rules file to use when reading CSV (default: FILE.rules)
+'--separator=CHAR'
+
+     Field separator to expect when reading CSV (default: ',')
 '--alias=OLD=NEW'
 
      rename accounts named OLD to NEW
@@ -209,7 +212,7 @@
 
 Tag Table:
 Node: Top72
-Node: OPTIONS3158
-Ref: #options3243
+Node: OPTIONS3160
+Ref: #options3245
 
 End Tag Table
diff --git a/embeddedfiles/hledger-web.txt b/embeddedfiles/hledger-web.txt
--- a/embeddedfiles/hledger-web.txt
+++ b/embeddedfiles/hledger-web.txt
@@ -105,6 +105,9 @@
               Conversion   rules  file  to  use  when  reading  CSV  (default:
               FILE.rules)
 
+       --separator=CHAR
+              Field separator to expect when reading CSV (default: `,')
+
        --alias=OLD=NEW
               rename accounts named OLD to NEW
 
@@ -248,4 +251,4 @@
 
 
 
-hledger-web 1.9.99                 June 2018                    hledger-web(1)
+hledger-web 1.10.99             September 2018                  hledger-web(1)
diff --git a/embeddedfiles/hledger.1 b/embeddedfiles/hledger.1
--- a/embeddedfiles/hledger.1
+++ b/embeddedfiles/hledger.1
@@ -1,6 +1,6 @@
 .\"t
 
-.TH "hledger" "1" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger" "1" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
@@ -188,6 +188,11 @@
 .RS
 .RE
 .TP
+.B \f[C]\-\-separator=CHAR\f[]
+Field separator to expect when reading CSV (default: `,')
+.RS
+.RE
+.TP
 .B \f[C]\-\-alias=OLD=NEW\f[]
 rename accounts named OLD to NEW
 .RS
@@ -2241,6 +2246,11 @@
 This was formerly called \[lq]equity\[rq], as in Ledger, and that alias
 is also accepted.
 See close \[en]help for more.
+.SS files
+.PP
+List all files included in the journal.
+With a REGEX argument, only file names matching the regular expression
+(case sensitive) are shown.
 .SS help
 .PP
 Show any of the hledger manuals.
@@ -2426,7 +2436,12 @@
 selection.
 .SS prices
 .PP
-Print all market prices from the journal.
+Print market price directives from the journal.
+With \[en]costs, also print synthetic market prices based on transaction
+prices.
+With \[en]inverted\-costs, also print inverse prices based on
+transaction prices.
+Prices (and postings providing prices) can be filtered by a query.
 .SS print
 .PP
 Show transactions from the journal.
@@ -2759,6 +2774,11 @@
 .SS rewrite
 .PP
 Print all transactions, adding custom postings to the matched ones.
+.SS roi
+.PP
+Shows time\-weighted (TWR) and money\-weighted (IRR) rate of return on
+your investments.
+See \f[C]roi\ \-\-help\f[] for more.
 .SS stats
 .PP
 Show some journal statistics.
@@ -2801,20 +2821,22 @@
 .SS test
 .PP
 Run built\-in unit tests.
-.IP
-.nf
-\f[C]
-$\ hledger\ test
-Cases:\ 74\ \ Tried:\ 74\ \ Errors:\ 0\ \ Failures:\ 0
-\f[]
-.fi
 .PP
-This command runs hledger's built\-in unit tests and displays a quick
-report.
-With a regular expression argument, it selects only tests with matching
-names.
-It's mainly used in development, but it's also nice to be able to check
-your hledger executable for smoke at any time.
+Prints test names and their results on stdout.
+If any test fails or gives an error, the exit code will be non\-zero.
+.PP
+Test names include a group prefix.
+If a (exact, case sensitive) group prefix, or a full test name is
+provided as the first argument, only that group or test is run.
+.PP
+If a numeric second argument is provided, it will set the randomness
+seed, for repeatable results from tests using randomness (currently none
+of them).
+.PP
+This is mainly used by developers, but it's nice to be able to
+sanity\-check your installed hledger executable at any time.
+All tests are expected to pass \- if you ever see otherwise, something
+has gone wrong, please report a bug!
 .SH ADD\-ON COMMANDS
 .PP
 hledger also searches for external add\-on commands, and will include
diff --git a/embeddedfiles/hledger.info b/embeddedfiles/hledger.info
--- a/embeddedfiles/hledger.info
+++ b/embeddedfiles/hledger.info
@@ -3,8 +3,8 @@
 
 File: hledger.info,  Node: Top,  Next: EXAMPLES,  Up: (dir)
 
-hledger(1) hledger 1.9.99
-*************************
+hledger(1) hledger 1.10.99
+**************************
 
 This is hledger's command-line interface (there are also curses and web
 interfaces).  Its basic function is to read a plain text file describing
@@ -164,6 +164,9 @@
 '--rules-file=RULESFILE'
 
      Conversion rules file to use when reading CSV (default: FILE.rules)
+'--separator=CHAR'
+
+     Field separator to expect when reading CSV (default: ',')
 '--alias=OLD=NEW'
 
      rename accounts named OLD to NEW
@@ -909,6 +912,7 @@
 * check-dates::
 * check-dupes::
 * close::
+* files::
 * help::
 * import::
 * incomestatement::
@@ -918,6 +922,7 @@
 * register::
 * register-match::
 * rewrite::
+* roi::
 * stats::
 * tags::
 * test::
@@ -1754,7 +1759,7 @@
 example: http://stefanorodighiero.net/software/hledger-dupes.html
 
 
-File: hledger.info,  Node: close,  Next: help,  Prev: check-dupes,  Up: COMMANDS
+File: hledger.info,  Node: close,  Next: files,  Prev: check-dupes,  Up: COMMANDS
 
 4.10 close
 ==========
@@ -1766,9 +1771,18 @@
 alias is also accepted.  See close -help for more.
 
 
-File: hledger.info,  Node: help,  Next: import,  Prev: close,  Up: COMMANDS
+File: hledger.info,  Node: files,  Next: help,  Prev: close,  Up: COMMANDS
 
-4.11 help
+4.11 files
+==========
+
+List all files included in the journal.  With a REGEX argument, only
+file names matching the regular expression (case sensitive) are shown.
+
+
+File: hledger.info,  Node: help,  Next: import,  Prev: files,  Up: COMMANDS
+
+4.12 help
 =========
 
 Show any of the hledger manuals.
@@ -1805,7 +1819,7 @@
 
 File: hledger.info,  Node: import,  Next: incomestatement,  Prev: help,  Up: COMMANDS
 
-4.12 import
+4.13 import
 ===========
 
 Read new transactions added to each FILE since last run, and add them to
@@ -1831,7 +1845,7 @@
 
 File: hledger.info,  Node: incomestatement,  Next: prices,  Prev: import,  Up: COMMANDS
 
-4.13 incomestatement
+4.14 incomestatement
 ====================
 
 This command displays a simple income statement, showing revenues and
@@ -1918,15 +1932,18 @@
 
 File: hledger.info,  Node: prices,  Next: print,  Prev: incomestatement,  Up: COMMANDS
 
-4.14 prices
+4.15 prices
 ===========
 
-Print all market prices from the journal.
+Print market price directives from the journal.  With -costs, also print
+synthetic market prices based on transaction prices.  With
+-inverted-costs, also print inverse prices based on transaction prices.
+Prices (and postings providing prices) can be filtered by a query.
 
 
 File: hledger.info,  Node: print,  Next: print-unique,  Prev: prices,  Up: COMMANDS
 
-4.15 print
+4.16 print
 ==========
 
 Show transactions from the journal.  Aliases: p, txns.
@@ -2043,7 +2060,7 @@
 
 File: hledger.info,  Node: print-unique,  Next: register,  Prev: print,  Up: COMMANDS
 
-4.16 print-unique
+4.17 print-unique
 =================
 
 Print transactions which do not reuse an already-seen description.
@@ -2051,7 +2068,7 @@
 
 File: hledger.info,  Node: register,  Next: register-match,  Prev: print-unique,  Up: COMMANDS
 
-4.17 register
+4.18 register
 =============
 
 Show postings and their running total.  Aliases: r, reg.
@@ -2156,7 +2173,7 @@
 
 File: hledger.info,  Node: Custom register output,  Up: register
 
-4.17.1 Custom register output
+4.18.1 Custom register output
 -----------------------------
 
 register uses the full terminal width by default, except on windows.
@@ -2187,7 +2204,7 @@
 
 File: hledger.info,  Node: register-match,  Next: rewrite,  Prev: register,  Up: COMMANDS
 
-4.18 register-match
+4.19 register-match
 ===================
 
 Print the one posting whose transaction description is closest to DESC,
@@ -2195,17 +2212,26 @@
 already-seen transactions when importing.
 
 
-File: hledger.info,  Node: rewrite,  Next: stats,  Prev: register-match,  Up: COMMANDS
+File: hledger.info,  Node: rewrite,  Next: roi,  Prev: register-match,  Up: COMMANDS
 
-4.19 rewrite
+4.20 rewrite
 ============
 
 Print all transactions, adding custom postings to the matched ones.
 
 
-File: hledger.info,  Node: stats,  Next: tags,  Prev: rewrite,  Up: COMMANDS
+File: hledger.info,  Node: roi,  Next: stats,  Prev: rewrite,  Up: COMMANDS
 
-4.20 stats
+4.21 roi
+========
+
+Shows time-weighted (TWR) and money-weighted (IRR) rate of return on
+your investments.  See 'roi --help' for more.
+
+
+File: hledger.info,  Node: stats,  Next: tags,  Prev: roi,  Up: COMMANDS
+
+4.22 stats
 ==========
 
 Show some journal statistics.
@@ -2237,7 +2263,7 @@
 
 File: hledger.info,  Node: tags,  Next: test,  Prev: stats,  Up: COMMANDS
 
-4.21 tags
+4.23 tags
 =========
 
 List all the tag names used in the journal.  With a TAGREGEX argument,
@@ -2248,19 +2274,27 @@
 
 File: hledger.info,  Node: test,  Prev: tags,  Up: COMMANDS
 
-4.22 test
+4.24 test
 =========
 
 Run built-in unit tests.
 
-$ hledger test
-Cases: 74  Tried: 74  Errors: 0  Failures: 0
+   Prints test names and their results on stdout.  If any test fails or
+gives an error, the exit code will be non-zero.
 
-   This command runs hledger's built-in unit tests and displays a quick
-report.  With a regular expression argument, it selects only tests with
-matching names.  It's mainly used in development, but it's also nice to
-be able to check your hledger executable for smoke at any time.
+   Test names include a group prefix.  If a (exact, case sensitive)
+group prefix, or a full test name is provided as the first argument,
+only that group or test is run.
 
+   If a numeric second argument is provided, it will set the randomness
+seed, for repeatable results from tests using randomness (currently none
+of them).
+
+   This is mainly used by developers, but it's nice to be able to
+sanity-check your installed hledger executable at any time.  All tests
+are expected to pass - if you ever see otherwise, something has gone
+wrong, please report a bug!
+
 
 File: hledger.info,  Node: ADD-ON COMMANDS,  Prev: COMMANDS,  Up: Top
 
@@ -2433,138 +2467,142 @@
 
 Tag Table:
 Node: Top68
-Node: EXAMPLES1888
-Ref: #examples1988
-Node: OPTIONS3634
-Ref: #options3736
-Node: General options4101
-Ref: #general-options4226
-Node: Command options6825
-Ref: #command-options6976
-Node: Command arguments7374
-Ref: #command-arguments7528
-Node: Argument files7649
-Ref: #argument-files7800
-Node: Special characters8066
-Ref: #special-characters8219
-Node: Input files9638
-Ref: #input-files9774
-Node: Smart dates11744
-Ref: #smart-dates11885
-Node: Report start & end date13291
-Ref: #report-start-end-date13461
-Node: Report intervals14526
-Ref: #report-intervals14689
-Node: Period expressions15090
-Ref: #period-expressions15250
-Node: Depth limiting19207
-Ref: #depth-limiting19351
-Node: Pivoting19693
-Ref: #pivoting19811
-Node: Cost21487
-Ref: #cost21595
-Node: Market value21713
-Ref: #market-value21848
-Node: Combining -B and -V23214
-Ref: #combining--b-and--v23377
-Node: Output destination23524
-Ref: #output-destination23686
-Node: Output format23969
-Ref: #output-format24121
-Node: Regular expressions24506
-Ref: #regular-expressions24643
-Node: QUERIES26004
-Ref: #queries26106
-Node: COMMANDS30068
-Ref: #commands30180
-Node: accounts31162
-Ref: #accounts31260
-Node: activity32506
-Ref: #activity32616
-Node: add32976
-Ref: #add33075
-Node: balance35736
-Ref: #balance35847
-Node: Classic balance report38930
-Ref: #classic-balance-report39103
-Node: Customising the classic balance report40472
-Ref: #customising-the-classic-balance-report40700
-Node: Colour support42774
-Ref: #colour-support42941
-Node: Flat mode43114
-Ref: #flat-mode43262
-Node: Depth limited balance reports43675
-Ref: #depth-limited-balance-reports43875
-Node: Multicolumn balance report44331
-Ref: #multicolumn-balance-report44529
-Node: Budget report49709
-Ref: #budget-report49852
-Ref: #output-format-152886
-Node: balancesheet52964
-Ref: #balancesheet53100
-Node: balancesheetequity55411
-Ref: #balancesheetequity55560
-Node: cashflow56097
-Ref: #cashflow56225
-Node: check-dates58348
-Ref: #check-dates58475
-Node: check-dupes58592
-Ref: #check-dupes58716
-Node: close58853
-Ref: #close58960
-Node: help59290
-Ref: #help59390
-Node: import60464
-Ref: #import60578
-Node: incomestatement61308
-Ref: #incomestatement61442
-Node: prices63846
-Ref: #prices63961
-Node: print64004
-Ref: #print64114
-Node: print-unique69008
-Ref: #print-unique69134
-Node: register69202
-Ref: #register69329
-Node: Custom register output73830
-Ref: #custom-register-output73959
-Node: register-match75189
-Ref: #register-match75323
-Node: rewrite75506
-Ref: #rewrite75623
-Node: stats75692
-Ref: #stats75795
-Node: tags76665
-Ref: #tags76763
-Node: test76999
-Ref: #test77083
-Node: ADD-ON COMMANDS77451
-Ref: #add-on-commands77561
-Node: Official add-ons78848
-Ref: #official-add-ons78988
-Node: api79075
-Ref: #api79164
-Node: ui79216
-Ref: #ui79315
-Node: web79373
-Ref: #web79462
-Node: Third party add-ons79508
-Ref: #third-party-add-ons79683
-Node: diff79818
-Ref: #diff79915
-Node: iadd80014
-Ref: #iadd80128
-Node: interest80211
-Ref: #interest80332
-Node: irr80427
-Ref: #irr80525
-Node: Experimental add-ons80603
-Ref: #experimental-add-ons80755
-Node: autosync81035
-Ref: #autosync81146
-Node: chart81385
-Ref: #chart81504
-Node: check81575
-Ref: #check81677
+Node: EXAMPLES1890
+Ref: #examples1990
+Node: OPTIONS3636
+Ref: #options3738
+Node: General options4103
+Ref: #general-options4228
+Node: Command options6910
+Ref: #command-options7061
+Node: Command arguments7459
+Ref: #command-arguments7613
+Node: Argument files7734
+Ref: #argument-files7885
+Node: Special characters8151
+Ref: #special-characters8304
+Node: Input files9723
+Ref: #input-files9859
+Node: Smart dates11829
+Ref: #smart-dates11970
+Node: Report start & end date13376
+Ref: #report-start-end-date13546
+Node: Report intervals14611
+Ref: #report-intervals14774
+Node: Period expressions15175
+Ref: #period-expressions15335
+Node: Depth limiting19292
+Ref: #depth-limiting19436
+Node: Pivoting19778
+Ref: #pivoting19896
+Node: Cost21572
+Ref: #cost21680
+Node: Market value21798
+Ref: #market-value21933
+Node: Combining -B and -V23299
+Ref: #combining--b-and--v23462
+Node: Output destination23609
+Ref: #output-destination23771
+Node: Output format24054
+Ref: #output-format24206
+Node: Regular expressions24591
+Ref: #regular-expressions24728
+Node: QUERIES26089
+Ref: #queries26191
+Node: COMMANDS30153
+Ref: #commands30265
+Node: accounts31265
+Ref: #accounts31363
+Node: activity32609
+Ref: #activity32719
+Node: add33079
+Ref: #add33178
+Node: balance35839
+Ref: #balance35950
+Node: Classic balance report39033
+Ref: #classic-balance-report39206
+Node: Customising the classic balance report40575
+Ref: #customising-the-classic-balance-report40803
+Node: Colour support42877
+Ref: #colour-support43044
+Node: Flat mode43217
+Ref: #flat-mode43365
+Node: Depth limited balance reports43778
+Ref: #depth-limited-balance-reports43978
+Node: Multicolumn balance report44434
+Ref: #multicolumn-balance-report44632
+Node: Budget report49812
+Ref: #budget-report49955
+Ref: #output-format-152989
+Node: balancesheet53067
+Ref: #balancesheet53203
+Node: balancesheetequity55514
+Ref: #balancesheetequity55663
+Node: cashflow56200
+Ref: #cashflow56328
+Node: check-dates58451
+Ref: #check-dates58578
+Node: check-dupes58695
+Ref: #check-dupes58819
+Node: close58956
+Ref: #close59064
+Node: files59394
+Ref: #files59495
+Node: help59636
+Ref: #help59736
+Node: import60810
+Ref: #import60924
+Node: incomestatement61654
+Ref: #incomestatement61788
+Node: prices64192
+Ref: #prices64307
+Node: print64579
+Ref: #print64689
+Node: print-unique69583
+Ref: #print-unique69709
+Node: register69777
+Ref: #register69904
+Node: Custom register output74405
+Ref: #custom-register-output74534
+Node: register-match75764
+Ref: #register-match75898
+Node: rewrite76081
+Ref: #rewrite76196
+Node: roi76265
+Ref: #roi76363
+Node: stats76479
+Ref: #stats76578
+Node: tags77448
+Ref: #tags77546
+Node: test77782
+Ref: #test77866
+Node: ADD-ON COMMANDS78574
+Ref: #add-on-commands78684
+Node: Official add-ons79971
+Ref: #official-add-ons80111
+Node: api80198
+Ref: #api80287
+Node: ui80339
+Ref: #ui80438
+Node: web80496
+Ref: #web80585
+Node: Third party add-ons80631
+Ref: #third-party-add-ons80806
+Node: diff80941
+Ref: #diff81038
+Node: iadd81137
+Ref: #iadd81251
+Node: interest81334
+Ref: #interest81455
+Node: irr81550
+Ref: #irr81648
+Node: Experimental add-ons81726
+Ref: #experimental-add-ons81878
+Node: autosync82158
+Ref: #autosync82269
+Node: chart82508
+Ref: #chart82627
+Node: check82698
+Ref: #check82800
 
 End Tag Table
diff --git a/embeddedfiles/hledger.txt b/embeddedfiles/hledger.txt
--- a/embeddedfiles/hledger.txt
+++ b/embeddedfiles/hledger.txt
@@ -134,6 +134,9 @@
               Conversion  rules  file  to  use  when  reading  CSV   (default:
               FILE.rules)
 
+       --separator=CHAR
+              Field separator to expect when reading CSV (default: `,')
+
        --alias=OLD=NEW
               rename accounts named OLD to NEW
 
@@ -332,10 +335,6 @@
        Examples:
 
 
-
-
-
-
        2004/10/1,     2004-01-01,            exact  date, several sepa-
        2004.9.1                              rators allowed.   Year  is
                                              4+  digits, month is 1-12,
@@ -398,6 +397,7 @@
                          rent month
        -p thismonth      all  transactions  in  the
                          current month
+
        date:2016/3/17-   the   above   written   as
                          queries instead
        date:-12/1
@@ -531,6 +531,7 @@
        -p "every 2nd Monday"  -  period bound-
        aries will be on second Monday of  each
        month
+
        -p "every 11/05"  - yearly periods with
        boundaries on 5th of Nov
        -p "every 5th Nov" - same
@@ -1595,6 +1596,10 @@
        a  period.   This  was formerly called "equity", as in Ledger, and that
        alias is also accepted.  See close -help for more.
 
+   files
+       List all files included in the journal.  With a  REGEX  argument,  only
+       file  names matching the regular expression (case sensitive) are shown.
+
    help
        Show any of the hledger manuals.
 
@@ -1727,13 +1732,16 @@
        tion.
 
    prices
-       Print all market prices from the journal.
+       Print market price directives from  the  journal.   With  -costs,  also
+       print  synthetic  market  prices  based  on  transaction  prices.  With
+       -inverted-costs, also print inverse prices based on transaction prices.
+       Prices (and postings providing prices) can be filtered by a query.
 
    print
        Show transactions from the journal.  Aliases: p, txns.
 
        -m STR --match=STR
-              show the transaction whose description is most similar  to  STR,
+              show  the  transaction whose description is most similar to STR,
               and is most recent
 
        --new  show only newer-dated transactions added in each file since last
@@ -1746,7 +1754,7 @@
               select the output format.  Supported formats: txt, csv.
 
        -o FILE --output-file=FILE
-              write output to FILE.  A file  extension  matching  one  of  the
+              write  output  to  FILE.   A  file extension matching one of the
               above formats selects that format.
 
               $ hledger print
@@ -1777,39 +1785,39 @@
        it does not preserve directives or inter-transaction comments
 
        Normally, the journal entry's explicit or implicit amount style is pre-
-       served.   Ie when an amount is omitted in the journal, it will be omit-
-       ted in the output.  You can use the  -x/--explicit  flag  to  make  all
+       served.  Ie when an amount is omitted in the journal, it will be  omit-
+       ted  in  the  output.   You  can use the -x/--explicit flag to make all
        amounts explicit, which can be useful for troubleshooting or for making
        your journal more readable and robust against data entry errors.  Note,
-       -x  will  cause postings with a multi-commodity amount (these can arise
-       when a multi-commodity transaction has  an  implicit  amount)  will  be
-       split  into  multiple single-commodity postings, for valid journal out-
+       -x will cause postings with a multi-commodity amount (these  can  arise
+       when  a  multi-commodity  transaction  has  an implicit amount) will be
+       split into multiple single-commodity postings, for valid  journal  out-
        put.
 
-       With -B/--cost, amounts with transaction prices are converted  to  cost
+       With  -B/--cost,  amounts with transaction prices are converted to cost
        using that price.  This can be used for troubleshooting.
 
-       With  -m/--match and a STR argument, print will show at most one trans-
-       action: the one one whose description is most similar to  STR,  and  is
-       most  recent.  STR should contain at least two characters.  If there is
+       With -m/--match and a STR argument, print will show at most one  trans-
+       action:  the  one  one whose description is most similar to STR, and is
+       most recent.  STR should contain at least two characters.  If there  is
        no similar-enough match, no transaction will be shown.
 
        With --new, for each FILE being read, hledger reads (and writes) a spe-
-       cial  state  file  (.latest.FILE in the same directory), containing the
-       latest transaction date(s) that were seen  last  time  FILE  was  read.
-       When  this  file  is found, only transactions with newer dates (and new
-       transactions on the latest date)  are  printed.   This  is  useful  for
-       ignoring  already-seen  entries  in import data, such as downloaded CSV
+       cial state file (.latest.FILE in the same  directory),  containing  the
+       latest  transaction  date(s)  that  were  seen last time FILE was read.
+       When this file is found, only transactions with newer  dates  (and  new
+       transactions  on  the  latest  date)  are  printed.  This is useful for
+       ignoring already-seen entries in import data, such  as  downloaded  CSV
        files.  Eg:
 
               $ hledger -f bank1.csv print --new
               # shows transactions added since last print --new on this file
 
-       This assumes that transactions  added  to  FILE  always  have  same  or
-       increasing  dates,  and  that  transactions  on the same day do not get
+       This  assumes  that  transactions  added  to  FILE  always have same or
+       increasing dates, and that transactions on the  same  day  do  not  get
        reordered.  See also the import command.
 
-       This command also supports output destination and output format  selec-
+       This  command also supports output destination and output format selec-
        tion.  Here's an example of print's CSV output:
 
               $ hledger print -Ocsv
@@ -1826,20 +1834,20 @@
               "5","2008/12/31","","*","","pay off","","liabilities:debts","1","$","","1","",""
               "5","2008/12/31","","*","","pay off","","assets:bank:checking","-1","$","1","","",""
 
-       o There  is  one  CSV record per posting, with the parent transaction's
+       o There is one CSV record per posting, with  the  parent  transaction's
          fields repeated.
 
        o The "txnidx" (transaction index) field shows which postings belong to
-         the  same transaction.  (This number might change if transactions are
-         reordered within the file, files are parsed/included in  a  different
+         the same transaction.  (This number might change if transactions  are
+         reordered  within  the file, files are parsed/included in a different
          order, etc.)
 
-       o The  amount  is  separated into "commodity" (the symbol) and "amount"
+       o The amount is separated into "commodity" (the  symbol)  and  "amount"
          (numeric quantity) fields.
 
        o The numeric amount is repeated in either the "credit" or "debit" col-
-         umn,  for convenience.  (Those names are not accurate in the account-
-         ing sense; it just puts negative amounts under  credit  and  zero  or
+         umn, for convenience.  (Those names are not accurate in the  account-
+         ing  sense;  it  just  puts negative amounts under credit and zero or
          greater amounts under debit.)
 
    print-unique
@@ -1852,7 +1860,7 @@
               show running total from report start date (default)
 
        -H --historical
-              show  historical running total/balance (includes postings before
+              show historical running total/balance (includes postings  before
               report start date)
 
        -A --average
@@ -1863,18 +1871,18 @@
               show postings' siblings instead
 
        -w N --width=N
-              set  output  width  (default:  terminal width or COLUMNS.  -wN,M
+              set output width (default: terminal  width  or  COLUMNS.   -wN,M
               sets description width as well)
 
        -O FMT --output-format=FMT
               select the output format.  Supported formats: txt, csv.
 
        -o FILE --output-file=FILE
-              write output to FILE.  A file  extension  matching  one  of  the
+              write  output  to  FILE.   A  file extension matching one of the
               above formats selects that format.
 
        The register command displays postings, one per line, and their running
-       total.  This is typically used with  a  query  selecting  a  particular
+       total.   This  is  typically  used  with a query selecting a particular
        account, to see that account's activity:
 
               $ hledger register checking
@@ -1883,8 +1891,8 @@
               2008/06/02 save                 assets:bank:checking           $-1            $1
               2008/12/31 pay off              assets:bank:checking           $-1             0
 
-       The  --historical/-H  flag  adds the balance from any undisplayed prior
-       postings to the running total.  This is useful when  you  want  to  see
+       The --historical/-H flag adds the balance from  any  undisplayed  prior
+       postings  to  the  running  total.  This is useful when you want to see
        only recent activity, with a historically accurate running balance:
 
               $ hledger register checking -b 2008/6 --historical
@@ -1894,23 +1902,23 @@
 
        The --depth option limits the amount of sub-account detail displayed.
 
-       The  --average/-A flag shows the running average posting amount instead
+       The --average/-A flag shows the running average posting amount  instead
        of the running total (so, the final number displayed is the average for
-       the  whole  report period).  This flag implies --empty (see below).  It
-       is affected by --historical.  It  works  best  when  showing  just  one
+       the whole report period).  This flag implies --empty (see  below).   It
+       is  affected  by  --historical.   It  works  best when showing just one
        account and one commodity.
 
-       The  --related/-r  flag shows the other postings in the transactions of
+       The --related/-r flag shows the other postings in the  transactions  of
        the postings which would normally be shown.
 
-       With a reporting interval, register shows  summary  postings,  one  per
+       With  a  reporting  interval,  register shows summary postings, one per
        interval, aggregating the postings to each account:
 
               $ hledger register --monthly income
               2008/01                 income:salary                          $-1           $-1
               2008/06                 income:gifts                           $-1           $-2
 
-       Periods  with no activity, and summary postings with a zero amount, are
+       Periods with no activity, and summary postings with a zero amount,  are
        not shown by default; use the --empty/-E flag to see them:
 
               $ hledger register --monthly income -E
@@ -1927,7 +1935,7 @@
               2008/11                                                          0           $-2
               2008/12                                                          0           $-2
 
-       Often, you'll want to see just one  line  per  interval.   The  --depth
+       Often,  you'll  want  to  see  just one line per interval.  The --depth
        option helps with this, causing subaccounts to be aggregated:
 
               $ hledger register --monthly assets --depth 1h
@@ -1935,18 +1943,18 @@
               2008/06                 assets                                 $-1             0
               2008/12                 assets                                 $-1           $-1
 
-       Note  when using report intervals, if you specify start/end dates these
-       will be adjusted outward if necessary to  contain  a  whole  number  of
-       intervals.   This  ensures  that  the first and last intervals are full
+       Note when using report intervals, if you specify start/end dates  these
+       will  be  adjusted  outward  if  necessary to contain a whole number of
+       intervals.  This ensures that the first and  last  intervals  are  full
        length and comparable to the others in the report.
 
    Custom register output
-       register uses the full terminal width by default,  except  on  windows.
-       You  can override this by setting the COLUMNS environment variable (not
+       register  uses  the  full terminal width by default, except on windows.
+       You can override this by setting the COLUMNS environment variable  (not
        a bash shell variable) or by using the --width/-w option.
 
-       The description and account columns normally share  the  space  equally
-       (about  half  of  (width  - 40) each).  You can adjust this by adding a
+       The  description  and  account columns normally share the space equally
+       (about half of (width - 40) each).  You can adjust  this  by  adding  a
        description  width  as  part  of  -width's  argument,  comma-separated:
        --width W,D .  Here's a diagram:
 
@@ -1963,17 +1971,21 @@
               $ hledger reg -w 100,40           # set overall width 100, description width 40
               $ hledger reg -w $COLUMNS,40      # use terminal width, and set description width
 
-       This  command also supports output destination and output format selec-
+       This command also supports output destination and output format  selec-
        tion.
 
    register-match
        Print the one posting whose transaction description is closest to DESC,
-       in  the  style  of  the register command.  Helps ledger-autosync detect
+       in the style of the register  command.   Helps  ledger-autosync  detect
        already-seen transactions when importing.
 
    rewrite
        Print all transactions, adding custom postings to the matched ones.
 
+   roi
+       Shows  time-weighted  (TWR)  and money-weighted (IRR) rate of return on
+       your investments.  See roi --help for more.
+
    stats
        Show some journal statistics.
 
@@ -2009,37 +2021,45 @@
    test
        Run built-in unit tests.
 
-              $ hledger test
-              Cases: 74  Tried: 74  Errors: 0  Failures: 0
+       Prints  test  names  and their results on stdout.  If any test fails or
+       gives an error, the exit code will be non-zero.
 
-       This  command  runs  hledger's built-in unit tests and displays a quick
-       report.  With a regular expression argument, it selects only tests with
-       matching names.  It's mainly used in development, but it's also nice to
-       be able to check your hledger executable for smoke at any time.
+       Test names include a group prefix.  If a (exact, case sensitive)  group
+       prefix,  or  a  full  test name is provided as the first argument, only
+       that group or test is run.
 
+       If a numeric second argument is provided, it will  set  the  randomness
+       seed,  for  repeatable  results  from tests using randomness (currently
+       none of them).
+
+       This is mainly used by developers, but it's nice to  be  able  to  san-
+       ity-check your installed hledger executable at any time.  All tests are
+       expected to pass - if you ever see otherwise, something has gone wrong,
+       please report a bug!
+
 ADD-ON COMMANDS
-       hledger also searches for external add-on commands,  and  will  include
+       hledger  also  searches  for external add-on commands, and will include
        these in the commands list.  These are programs or scripts in your PATH
-       whose name starts with hledger- and ends with a recognised file  exten-
+       whose  name starts with hledger- and ends with a recognised file exten-
        sion (currently: no extension, bat,com,exe, hs,lhs,pl,py,rb,rkt,sh).
 
-       Add-ons  can  be  invoked like any hledger command, but there are a few
+       Add-ons can be invoked like any hledger command, but there  are  a  few
        things to be aware of.  Eg if the hledger-web add-on is installed,
 
        o hledger -h web  shows  hledger's  help,  while  hledger web -h  shows
          hledger-web's help.
 
-       o Flags  specific  to  the add-on must have a preceding -- to hide them
-         from hledger.  So hledger web --serve --port 9000 will  be  rejected;
+       o Flags specific to the add-on must have a preceding --  to  hide  them
+         from  hledger.   So hledger web --serve --port 9000 will be rejected;
          you must use hledger web -- --serve --port 9000.
 
-       o You    can    always    run    add-ons    directly    if   preferred:
+       o You   can    always    run    add-ons    directly    if    preferred:
          hledger-web --serve --port 9000.
 
-       Add-ons are a relatively easy way to add local features  or  experiment
-       with  new  ideas.   They  can  be  written in any language, but haskell
-       scripts have a big advantage:  they  can  use  the  same  hledger  (and
-       haskell)  library functions that built-in commands do, for command-line
+       Add-ons  are  a relatively easy way to add local features or experiment
+       with new ideas.  They can be  written  in  any  language,  but  haskell
+       scripts  have  a  big  advantage:  they  can  use the same hledger (and
+       haskell) library functions that built-in commands do, for  command-line
        options, journal parsing, reporting, etc.
 
        Here are some hledger add-ons available:
@@ -2057,7 +2077,7 @@
        hledger-web provides a simple web interface.
 
    Third party add-ons
-       These are maintained separately, and usually updated  shortly  after  a
+       These  are  maintained  separately, and usually updated shortly after a
        hledger release.
 
    diff
@@ -2065,7 +2085,7 @@
        journal file and another.
 
    iadd
-       hledger-iadd is a curses-style, more interactive  replacement  for  the
+       hledger-iadd  is  a  curses-style, more interactive replacement for the
        add command.
 
    interest
@@ -2073,19 +2093,19 @@
        ing to various schemes.
 
    irr
-       hledger-irr calculates the internal rate of  return  of  an  investment
+       hledger-irr  calculates  the  internal  rate of return of an investment
        account.
 
    Experimental add-ons
-       These  are  available  in source form in the hledger repo's bin/ direc-
+       These are available in source form in the hledger  repo's  bin/  direc-
        tory; installing them is pretty easy.  They may be less mature and doc-
-       umented  than  built-in commands.  Reading and tweaking these is a good
+       umented than built-in commands.  Reading and tweaking these is  a  good
        way to start making your own!
 
    autosync
        hledger-autosync is a symbolic link for easily running ledger-autosync,
-       if  installed.   ledger-autosync  does  deduplicating conversion of OFX
-       data and some CSV formats, and can also download the data if your  bank
+       if installed.  ledger-autosync does  deduplicating  conversion  of  OFX
+       data  and some CSV formats, and can also download the data if your bank
        offers OFX Direct Connect.
 
    chart
@@ -2095,21 +2115,21 @@
        hledger-check.hs checks more powerful account balance assertions.
 
 ENVIRONMENT
-       COLUMNS  The  screen  width used by the register command.  Default: the
+       COLUMNS The screen width used by the register  command.   Default:  the
        full terminal width.
 
        LEDGER_FILE The journal file path when not specified with -f.  Default:
-       ~/.hledger.journal  (on  windows,  perhaps C:/Users/USER/.hledger.jour-
+       ~/.hledger.journal (on  windows,  perhaps  C:/Users/USER/.hledger.jour-
        nal).
 
 FILES
-       Reads data from one or more files in hledger journal, timeclock,  time-
-       dot,   or   CSV   format   specified   with  -f,  or  $LEDGER_FILE,  or
-       $HOME/.hledger.journal          (on          windows,           perhaps
+       Reads  data from one or more files in hledger journal, timeclock, time-
+       dot,  or  CSV  format  specified   with   -f,   or   $LEDGER_FILE,   or
+       $HOME/.hledger.journal           (on          windows,          perhaps
        C:/Users/USER/.hledger.journal).
 
 BUGS
-       The  need  to  precede  addon command options with -- when invoked from
+       The need to precede addon command options with  --  when  invoked  from
        hledger is awkward.
 
        When input data contains non-ascii characters, a suitable system locale
@@ -2122,33 +2142,33 @@
        In a Cygwin/MSYS/Mintty window, the tab key is not supported in hledger
        add.
 
-       Not all of Ledger's journal file syntax is supported.  See file  format
+       Not  all of Ledger's journal file syntax is supported.  See file format
        differences.
 
-       On  large  data  files,  hledger  is  slower  and uses more memory than
+       On large data files, hledger  is  slower  and  uses  more  memory  than
        Ledger.
 
 TROUBLESHOOTING
-       Here are some issues you might encounter  when  you  run  hledger  (and
-       remember  you can also seek help from the IRC channel, mail list or bug
+       Here  are  some  issues  you  might encounter when you run hledger (and
+       remember you can also seek help from the IRC channel, mail list or  bug
        tracker):
 
        Successfully installed, but "No command `hledger' found"
        stack and cabal install binaries into a special directory, which should
-       be  added  to your PATH environment variable.  Eg on unix-like systems,
+       be added to your PATH environment variable.  Eg on  unix-like  systems,
        that is ~/.local/bin and ~/.cabal/bin respectively.
 
        I set a custom LEDGER_FILE, but hledger is still using the default file
-       LEDGER_FILE  should  be  a  real environment variable, not just a shell
-       variable.  The command env | grep LEDGER_FILE should show it.  You  may
+       LEDGER_FILE should be a real environment variable,  not  just  a  shell
+       variable.   The command env | grep LEDGER_FILE should show it.  You may
        need to use export.  Here's an explanation.
 
-       "Illegal  byte  sequence"  or  "Invalid or incomplete multibyte or wide
+       "Illegal byte sequence" or "Invalid or  incomplete  multibyte  or  wide
        character" errors
        In order to handle non-ascii letters and symbols (like ), hledger needs
        an appropriate locale.  This is usually configured system-wide; you can
        also configure it temporarily.  The locale may need to be one that sup-
-       ports  UTF-8,  if you built hledger with GHC < 7.2 (or possibly always,
+       ports UTF-8, if you built hledger with GHC < 7.2 (or  possibly  always,
        I'm not sure yet).
 
        Here's  an  example  of  setting  the  locale  temporarily,  on  ubuntu
@@ -2167,7 +2187,7 @@
               $ echo "export LANG=en_US.UTF-8" >>~/.bash_profile
               $ bash --login
 
-       If  we  preferred  to  use eg fr_FR.utf8, we might have to install that
+       If we preferred to use eg fr_FR.utf8, we might  have  to  install  that
        first:
 
               $ apt-get install language-pack-fr
@@ -2188,7 +2208,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)
 
 
@@ -2202,7 +2222,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)
 
@@ -2210,4 +2230,4 @@
 
 
 
-hledger 1.9.99                     June 2018                        hledger(1)
+hledger 1.10.99                 September 2018                      hledger(1)
diff --git a/embeddedfiles/hledger_csv.5 b/embeddedfiles/hledger_csv.5
--- a/embeddedfiles/hledger_csv.5
+++ b/embeddedfiles/hledger_csv.5
@@ -1,5 +1,5 @@
 
-.TH "hledger_csv" "5" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger_csv" "5" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
diff --git a/embeddedfiles/hledger_csv.info b/embeddedfiles/hledger_csv.info
--- a/embeddedfiles/hledger_csv.info
+++ b/embeddedfiles/hledger_csv.info
@@ -3,8 +3,8 @@
 
 File: hledger_csv.info,  Node: Top,  Next: CSV RULES,  Up: (dir)
 
-hledger_csv(5) hledger 1.9.99
-*****************************
+hledger_csv(5) hledger 1.10.99
+******************************
 
 hledger can read CSV (comma-separated value) files as if they were
 journal files, automatically converting each CSV record into a
@@ -317,33 +317,33 @@
 
 Tag Table:
 Node: Top72
-Node: CSV RULES2167
-Ref: #csv-rules2275
-Node: skip2537
-Ref: #skip2631
-Node: date-format2803
-Ref: #date-format2930
-Node: field list3436
-Ref: #field-list3573
-Node: field assignment4278
-Ref: #field-assignment4433
-Node: conditional block4937
-Ref: #conditional-block5091
-Node: include5987
-Ref: #include6117
-Node: newest-first6348
-Ref: #newest-first6462
-Node: CSV TIPS6873
-Ref: #csv-tips6967
-Node: CSV ordering7085
-Ref: #csv-ordering7203
-Node: CSV accounts7384
-Ref: #csv-accounts7522
-Node: CSV amounts7776
-Ref: #csv-amounts7922
-Node: CSV balance assertions8697
-Ref: #csv-balance-assertions8879
-Node: Reading multiple CSV files9084
-Ref: #reading-multiple-csv-files9254
+Node: CSV RULES2169
+Ref: #csv-rules2277
+Node: skip2539
+Ref: #skip2633
+Node: date-format2805
+Ref: #date-format2932
+Node: field list3438
+Ref: #field-list3575
+Node: field assignment4280
+Ref: #field-assignment4435
+Node: conditional block4939
+Ref: #conditional-block5093
+Node: include5989
+Ref: #include6119
+Node: newest-first6350
+Ref: #newest-first6464
+Node: CSV TIPS6875
+Ref: #csv-tips6969
+Node: CSV ordering7087
+Ref: #csv-ordering7205
+Node: CSV accounts7386
+Ref: #csv-accounts7524
+Node: CSV amounts7778
+Ref: #csv-amounts7924
+Node: CSV balance assertions8699
+Ref: #csv-balance-assertions8881
+Node: Reading multiple CSV files9086
+Ref: #reading-multiple-csv-files9256
 
 End Tag Table
diff --git a/embeddedfiles/hledger_csv.txt b/embeddedfiles/hledger_csv.txt
--- a/embeddedfiles/hledger_csv.txt
+++ b/embeddedfiles/hledger_csv.txt
@@ -249,4 +249,4 @@
 
 
 
-hledger 1.9.99                     June 2018                    hledger_csv(5)
+hledger 1.10.99                 September 2018                  hledger_csv(5)
diff --git a/embeddedfiles/hledger_journal.5 b/embeddedfiles/hledger_journal.5
--- a/embeddedfiles/hledger_journal.5
+++ b/embeddedfiles/hledger_journal.5
@@ -1,6 +1,6 @@
 .\"t
 
-.TH "hledger_journal" "5" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger_journal" "5" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
@@ -1011,7 +1011,8 @@
 .PP
 If the path does not begin with a slash, it is relative to the current
 file.
-Glob patterns (\f[C]*\f[]) are not currently supported.
+The include file path may contain common glob patterns (e.g.
+\f[C]*\f[]).
 .PP
 The \f[C]include\f[] directive can only be used in journal files.
 It can include journal, timeclock or timedot files, but not CSV files.
@@ -1158,54 +1159,84 @@
 .PD
 In future it will also help detect misspelled accounts.
 .PP
-Account names can be followed by a numeric account code:
+An account directive can also have indented subdirectives following it,
+which are currently ignored.
+Here is the full syntax:
 .IP
 .nf
 \f[C]
-account\ assets\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1000
-account\ assets:bank:checking\ \ \ \ 1110
-account\ liabilities\ \ \ \ \ \ \ \ \ \ \ \ \ 2000
-account\ revenues\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 4000
-account\ expenses\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 6000
+;\ account\ ACCTNAME
+;\ \ \ [OPTIONALSUBDIRECTIVES]
+
+account\ assets:bank:checking
+\ \ a\ comment
+\ \ some\-tag:12345
 \f[]
 .fi
+.SS Account display order
 .PP
-This affects how accounts are sorted in account and balance reports:
-accounts with codes are listed before accounts without codes, and in
-increasing code order (instead of listing all accounts alphabetically).
-Warning, this feature is incomplete; account codes do not yet affect
-sort order in
-.IP \[bu] 2
-the \f[C]accounts\f[] command
-.IP \[bu] 2
-the \f[C]balance\f[] command's single\-column mode
-.IP \[bu] 2
-flat mode balance reports (to work around this, declare account codes on
-the subaccounts as well).
-.IP \[bu] 2
-hledger\-web's sidebar
+Account directives have another purpose: they set the order in which
+accounts are displayed, in hledger reports, hledger\-ui accounts screen,
+hledger\-web sidebar etc.
+For example, say you have these top\-level accounts:
+.IP
+.nf
+\f[C]
+$\ accounts\ \-1
+assets
+equity
+expenses
+liabilities
+misc
+other
+revenues
+\f[]
+.fi
 .PP
-Account codes should be all numeric digits, unique, and separated from
-the account name by at least two spaces (since account names may contain
-single spaces).
-By convention, often the first digit indicates the type of account, as
-in this numbering scheme and the example above.
-In future, we might use this to recognize account types.
+By default, they are displayed in alphabetical order.
+But if you add the following account directives to the journal:
+.IP
+.nf
+\f[C]
+account\ assets
+account\ liabilities
+account\ equity
+account\ revenues
+account\ expenses
+\f[]
+.fi
 .PP
-An account directive can also have indented subdirectives following it,
-which are currently ignored.
-Here is the full syntax:
+the display order changes to:
 .IP
 .nf
 \f[C]
-;\ account\ ACCTNAME\ \ [OPTIONALCODE]
-;\ \ \ [OPTIONALSUBDIRECTIVES]
-
-account\ assets:bank:checking\ \ \ 1110
-\ \ a\ comment
-\ \ some\-tag:12345
+$\ accounts\ \-1
+assets
+liabilities
+equity
+revenues
+expenses
+misc
+other
 \f[]
 .fi
+.PP
+Ie, declared accounts first, in the order they were declared, followed
+by any undeclared accounts in alphabetic order.
+.PP
+Note that sorting is done at each level of the account tree (within each
+group of sibling accounts under the same parent).
+This directive:
+.IP
+.nf
+\f[C]
+account\ other:zoo
+\f[]
+.fi
+.PP
+would influence the position of \f[C]zoo\f[] among \f[C]other\f[]'s
+subaccounts, but not the position of \f[C]other\f[] among the top\-level
+accounts.
 .SS Rewriting accounts
 .PP
 You can define account alias rules which rewrite your account names, or
@@ -1373,7 +1404,7 @@
 .PP
 A periodic transaction rule looks like a normal journal entry, with the
 date replaced by a tilde (\f[C]~\f[]) followed by a period expression
-(mnemonic: \f[C]~\f[] looks like a repeating sine wave):
+(mnemonic: \f[C]~\f[] looks like a recurring sine wave.):
 .IP
 .nf
 \f[C]
@@ -1410,11 +1441,26 @@
 They will look like normal transactions, but with an extra tag named
 \f[C]recur\f[], whose value is the generating period expression.
 .PP
-Forecast transactions begin on or after the day after the latest normal
-(non\-periodic) transaction in the journal, or today if there are none.
+Forecast transactions start on the first occurrence, and end on the last
+occurrence, of their interval within the forecast period.
+The forecast period:
+.IP \[bu] 2
+begins on the later of
+.RS 2
+.IP \[bu] 2
+the report start date if specified with \-b/\-p/date:
+.IP \[bu] 2
+the day after the latest normal (non\-periodic) transaction in the
+journal, or today if there are no normal transactions.
+.RE
+.IP \[bu] 2
+ends on the report end date if specified with \-e/\-p/date:, or 180 days
+from today.
 .PP
-They end on or before the report end date if specified, or 180 days from
-today if unspecified.
+where \[lq]today\[rq] means the current date at report time.
+The \[lq]later of\[rq] rule ensures that forecast transactions do not
+overlap normal transactions in time; they will begin only after normal
+transactions end.
 .PP
 Forecasting can be useful for estimating balances into the future, and
 experimenting with different scenarios.
@@ -1440,15 +1486,18 @@
 .PP
 For more details, see: balance: Budget report and Cookbook: Budgeting
 and Forecasting.
-.SS Automated postings
 .PP
-Automated posting rules describe extra postings that should be added to
-certain transactions at report time, when the \f[C]\-\-auto\f[] flag is
-used.
+.SS Transaction Modifiers
 .PP
-An automated posting rule looks like a normal journal entry, except the
-first line is an equal sign (\f[C]=\f[]) followed by a query (mnemonic:
-\f[C]=\f[] looks like posting lines):
+Transaction modifier rules describe changes that should be applied
+automatically to certain transactions.
+Currently, this means adding extra postings (also known as
+\[lq]automated postings\[rq]).
+Transaction modifiers are enabled by the \f[C]\-\-auto\f[] flag.
+.PP
+A transaction modifier rule looks a bit like a normal journal entry,
+except the first line is an equal sign (\f[C]=\f[]) followed by a query
+(mnemonic: \f[C]=\f[] suggests matching something.):
 .IP
 .nf
 \f[C]
diff --git a/embeddedfiles/hledger_journal.info b/embeddedfiles/hledger_journal.info
--- a/embeddedfiles/hledger_journal.info
+++ b/embeddedfiles/hledger_journal.info
@@ -4,8 +4,8 @@
 
 File: hledger_journal.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir)
 
-hledger_journal(5) hledger 1.9.99
-*********************************
+hledger_journal(5) hledger 1.10.99
+**********************************
 
 hledger's usual data source is a plain text file containing journal
 entries in hledger journal format.  This file represents a standard
@@ -82,7 +82,7 @@
 * Tags::
 * Directives::
 * Periodic transactions::
-* Automated postings::
+* Transaction Modifiers::
 
 
 File: hledger_journal.info,  Node: Transactions,  Next: Postings,  Up: FILE FORMAT
@@ -853,6 +853,7 @@
 * Default commodity::
 * Market prices::
 * Declaring accounts::
+* Account display order::
 * Rewriting accounts::
 * Default parent account::
 
@@ -878,7 +879,8 @@
 include path/to/file.journal
 
    If the path does not begin with a slash, it is relative to the
-current file.  Glob patterns ('*') are not currently supported.
+current file.  The include file path may contain common glob patterns
+(e.g.  '*').
 
    The 'include' directive can only be used in journal files.  It can
 include journal, timeclock or timedot files, but not CSV files.
@@ -1001,7 +1003,7 @@
 another commodity using these prices.
 
 
-File: hledger_journal.info,  Node: Declaring accounts,  Next: Rewriting accounts,  Prev: Market prices,  Up: Directives
+File: hledger_journal.info,  Node: Declaring accounts,  Next: Account display order,  Prev: Market prices,  Up: Directives
 
 1.14.7 Declaring accounts
 -------------------------
@@ -1015,46 +1017,71 @@
 hledger add, hledger-iadd, hledger-web, and ledger-mode.
 In future it will also help detect misspelled accounts.
 
-   Account names can be followed by a numeric account code:
-
-account assets                  1000
-account assets:bank:checking    1110
-account liabilities             2000
-account revenues                4000
-account expenses                6000
-
-   This affects how accounts are sorted in account and balance reports:
-accounts with codes are listed before accounts without codes, and in
-increasing code order (instead of listing all accounts alphabetically).
-Warning, this feature is incomplete; account codes do not yet affect
-sort order in
-
-   * the 'accounts' command
-   * the 'balance' command's single-column mode
-   * flat mode balance reports (to work around this, declare account
-     codes on the subaccounts as well).
-   * hledger-web's sidebar
-
-   Account codes should be all numeric digits, unique, and separated
-from the account name by at least two spaces (since account names may
-contain single spaces).  By convention, often the first digit indicates
-the type of account, as in this numbering scheme and the example above.
-In future, we might use this to recognize account types.
-
    An account directive can also have indented subdirectives following
 it, which are currently ignored.  Here is the full syntax:
 
-; account ACCTNAME  [OPTIONALCODE]
+; account ACCTNAME
 ;   [OPTIONALSUBDIRECTIVES]
 
-account assets:bank:checking   1110
+account assets:bank:checking
   a comment
   some-tag:12345
 
 
-File: hledger_journal.info,  Node: Rewriting accounts,  Next: Default parent account,  Prev: Declaring accounts,  Up: Directives
+File: hledger_journal.info,  Node: Account display order,  Next: Rewriting accounts,  Prev: Declaring accounts,  Up: Directives
 
-1.14.8 Rewriting accounts
+1.14.8 Account display order
+----------------------------
+
+Account directives have another purpose: they set the order in which
+accounts are displayed, in hledger reports, hledger-ui accounts screen,
+hledger-web sidebar etc.  For example, say you have these top-level
+accounts:
+
+$ accounts -1
+assets
+equity
+expenses
+liabilities
+misc
+other
+revenues
+
+   By default, they are displayed in alphabetical order.  But if you add
+the following account directives to the journal:
+
+account assets
+account liabilities
+account equity
+account revenues
+account expenses
+
+   the display order changes to:
+
+$ accounts -1
+assets
+liabilities
+equity
+revenues
+expenses
+misc
+other
+
+   Ie, declared accounts first, in the order they were declared,
+followed by any undeclared accounts in alphabetic order.
+
+   Note that sorting is done at each level of the account tree (within
+each group of sibling accounts under the same parent).  This directive:
+
+account other:zoo
+
+   would influence the position of 'zoo' among 'other''s subaccounts,
+but not the position of 'other' among the top-level accounts.
+
+
+File: hledger_journal.info,  Node: Rewriting accounts,  Next: Default parent account,  Prev: Account display order,  Up: Directives
+
+1.14.9 Rewriting accounts
 -------------------------
 
 You can define account alias rules which rewrite your account names, or
@@ -1082,7 +1109,7 @@
 
 File: hledger_journal.info,  Node: Basic aliases,  Next: Regex aliases,  Up: Rewriting accounts
 
-1.14.8.1 Basic aliases
+1.14.9.1 Basic aliases
 ......................
 
 To set an account alias, use the 'alias' directive in your journal file.
@@ -1105,7 +1132,7 @@
 
 File: hledger_journal.info,  Node: Regex aliases,  Next: Multiple aliases,  Prev: Basic aliases,  Up: Rewriting accounts
 
-1.14.8.2 Regex aliases
+1.14.9.2 Regex aliases
 ......................
 
 There is also a more powerful variant that uses a regular expression,
@@ -1130,7 +1157,7 @@
 
 File: hledger_journal.info,  Node: Multiple aliases,  Next: end aliases,  Prev: Regex aliases,  Up: Rewriting accounts
 
-1.14.8.3 Multiple aliases
+1.14.9.3 Multiple aliases
 .........................
 
 You can define as many aliases as you like using directives or
@@ -1146,7 +1173,7 @@
 
 File: hledger_journal.info,  Node: end aliases,  Prev: Multiple aliases,  Up: Rewriting accounts
 
-1.14.8.4 'end aliases'
+1.14.9.4 'end aliases'
 ......................
 
 You can clear (forget) all currently defined aliases with the 'end
@@ -1157,8 +1184,8 @@
 
 File: hledger_journal.info,  Node: Default parent account,  Prev: Rewriting accounts,  Up: Directives
 
-1.14.9 Default parent account
------------------------------
+1.14.10 Default parent account
+------------------------------
 
 You can specify a parent account which will be prepended to all accounts
 within a section of the journal.  Use the 'apply account' and 'end apply
@@ -1196,7 +1223,7 @@
 parent account.
 
 
-File: hledger_journal.info,  Node: Periodic transactions,  Next: Automated postings,  Prev: Directives,  Up: FILE FORMAT
+File: hledger_journal.info,  Node: Periodic transactions,  Next: Transaction Modifiers,  Prev: Directives,  Up: FILE FORMAT
 
 1.15 Periodic transactions
 ==========================
@@ -1208,7 +1235,7 @@
 
    A periodic transaction rule looks like a normal journal entry, with
 the date replaced by a tilde ('~') followed by a period expression
-(mnemonic: '~' looks like a repeating sine wave):
+(mnemonic: '~' looks like a recurring sine wave.):
 
 ~ monthly
     expenses:rent          $2000
@@ -1245,13 +1272,23 @@
 normal transactions, but with an extra tag named 'recur', whose value is
 the generating period expression.
 
-   Forecast transactions begin on or after the day after the latest
-normal (non-periodic) transaction in the journal, or today if there are
-none.
+   Forecast transactions start on the first occurrence, and end on the
+last occurrence, of their interval within the forecast period.  The
+forecast period:
 
-   They end on or before the report end date if specified, or 180 days
-from today if unspecified.
+   * begins on the later of
+        * the report start date if specified with -b/-p/date:
+        * the day after the latest normal (non-periodic) transaction in
+          the journal, or today if there are no normal transactions.
 
+   * ends on the report end date if specified with -e/-p/date:, or 180
+     days from today.
+
+   where "today" means the current date at report time.  The "later of"
+rule ensures that forecast transactions do not overlap normal
+transactions in time; they will begin only after normal transactions
+end.
+
    Forecasting can be useful for estimating balances into the future,
 and experimenting with different scenarios.  Note the start date logic
 means that forecasted transactions are automatically replaced by normal
@@ -1283,17 +1320,19 @@
 and Forecasting.
 
 
-File: hledger_journal.info,  Node: Automated postings,  Prev: Periodic transactions,  Up: FILE FORMAT
+File: hledger_journal.info,  Node: Transaction Modifiers,  Prev: Periodic transactions,  Up: FILE FORMAT
 
-1.16 Automated postings
-=======================
+1.16 Transaction Modifiers
+==========================
 
-Automated posting rules describe extra postings that should be added to
-certain transactions at report time, when the '--auto' flag is used.
+Transaction modifier rules describe changes that should be applied
+automatically to certain transactions.  Currently, this means adding
+extra postings (also known as "automated postings").  Transaction
+modifiers are enabled by the '--auto' flag.
 
-   An automated posting rule looks like a normal journal entry, except
-the first line is an equal sign ('=') followed by a query (mnemonic: '='
-looks like posting lines):
+   A transaction modifier rule looks a bit like a normal journal entry,
+except the first line is an equal sign ('=') followed by a query
+(mnemonic: '=' suggests matching something.):
 
 = expenses:gifts
     budget:gifts  *-1
@@ -1354,91 +1393,93 @@
 
 Tag Table:
 Node: Top76
-Node: FILE FORMAT2376
-Ref: #file-format2500
-Node: Transactions2784
-Ref: #transactions2905
-Node: Postings3589
-Ref: #postings3716
-Node: Dates4711
-Ref: #dates4826
-Node: Simple dates4891
-Ref: #simple-dates5017
-Node: Secondary dates5383
-Ref: #secondary-dates5537
-Node: Posting dates7100
-Ref: #posting-dates7229
-Node: Status8603
-Ref: #status8723
-Node: Description10431
-Ref: #description10569
-Node: Payee and note10888
-Ref: #payee-and-note11002
-Node: Account names11244
-Ref: #account-names11387
-Node: Amounts11874
-Ref: #amounts12010
-Node: Virtual Postings15027
-Ref: #virtual-postings15186
-Node: Balance Assertions16406
-Ref: #balance-assertions16581
-Node: Assertions and ordering17477
-Ref: #assertions-and-ordering17663
-Node: Assertions and included files18363
-Ref: #assertions-and-included-files18604
-Node: Assertions and multiple -f options18937
-Ref: #assertions-and-multiple--f-options19191
-Node: Assertions and commodities19323
-Ref: #assertions-and-commodities19558
-Node: Assertions and subaccounts20254
-Ref: #assertions-and-subaccounts20486
-Node: Assertions and virtual postings21007
-Ref: #assertions-and-virtual-postings21214
-Node: Balance Assignments21356
-Ref: #balance-assignments21537
-Node: Transaction prices22657
-Ref: #transaction-prices22826
-Node: Comments25094
-Ref: #comments25228
-Node: Tags26398
-Ref: #tags26516
-Node: Directives27918
-Ref: #directives28061
-Node: Comment blocks33917
-Ref: #comment-blocks34062
-Node: Including other files34238
-Ref: #including-other-files34418
-Node: Default year34807
-Ref: #default-year34976
-Node: Declaring commodities35399
-Ref: #declaring-commodities35582
-Node: Default commodity36809
-Ref: #default-commodity36985
-Node: Market prices37621
-Ref: #market-prices37786
-Node: Declaring accounts38627
-Ref: #declaring-accounts38803
-Node: Rewriting accounts40474
-Ref: #rewriting-accounts40659
-Node: Basic aliases41393
-Ref: #basic-aliases41539
-Node: Regex aliases42243
-Ref: #regex-aliases42414
-Node: Multiple aliases43132
-Ref: #multiple-aliases43307
-Node: end aliases43805
-Ref: #end-aliases43952
-Node: Default parent account44053
-Ref: #default-parent-account44219
-Node: Periodic transactions45103
-Ref: #periodic-transactions45282
-Node: Forecasting with periodic transactions46492
-Ref: #forecasting-with-periodic-transactions46735
-Node: Budgeting with periodic transactions47976
-Ref: #budgeting-with-periodic-transactions48215
-Node: Automated postings48674
-Ref: #automated-postings48828
-Node: EDITOR SUPPORT49967
-Ref: #editor-support50085
+Node: FILE FORMAT2378
+Ref: #file-format2502
+Node: Transactions2789
+Ref: #transactions2910
+Node: Postings3594
+Ref: #postings3721
+Node: Dates4716
+Ref: #dates4831
+Node: Simple dates4896
+Ref: #simple-dates5022
+Node: Secondary dates5388
+Ref: #secondary-dates5542
+Node: Posting dates7105
+Ref: #posting-dates7234
+Node: Status8608
+Ref: #status8728
+Node: Description10436
+Ref: #description10574
+Node: Payee and note10893
+Ref: #payee-and-note11007
+Node: Account names11249
+Ref: #account-names11392
+Node: Amounts11879
+Ref: #amounts12015
+Node: Virtual Postings15032
+Ref: #virtual-postings15191
+Node: Balance Assertions16411
+Ref: #balance-assertions16586
+Node: Assertions and ordering17482
+Ref: #assertions-and-ordering17668
+Node: Assertions and included files18368
+Ref: #assertions-and-included-files18609
+Node: Assertions and multiple -f options18942
+Ref: #assertions-and-multiple--f-options19196
+Node: Assertions and commodities19328
+Ref: #assertions-and-commodities19563
+Node: Assertions and subaccounts20259
+Ref: #assertions-and-subaccounts20491
+Node: Assertions and virtual postings21012
+Ref: #assertions-and-virtual-postings21219
+Node: Balance Assignments21361
+Ref: #balance-assignments21542
+Node: Transaction prices22662
+Ref: #transaction-prices22831
+Node: Comments25099
+Ref: #comments25233
+Node: Tags26403
+Ref: #tags26521
+Node: Directives27923
+Ref: #directives28066
+Node: Comment blocks33948
+Ref: #comment-blocks34093
+Node: Including other files34269
+Ref: #including-other-files34449
+Node: Default year34857
+Ref: #default-year35026
+Node: Declaring commodities35449
+Ref: #declaring-commodities35632
+Node: Default commodity36859
+Ref: #default-commodity37035
+Node: Market prices37671
+Ref: #market-prices37836
+Node: Declaring accounts38677
+Ref: #declaring-accounts38856
+Node: Account display order39406
+Ref: #account-display-order39596
+Node: Rewriting accounts40617
+Ref: #rewriting-accounts40805
+Node: Basic aliases41539
+Ref: #basic-aliases41685
+Node: Regex aliases42389
+Ref: #regex-aliases42560
+Node: Multiple aliases43278
+Ref: #multiple-aliases43453
+Node: end aliases43951
+Ref: #end-aliases44098
+Node: Default parent account44199
+Ref: #default-parent-account44367
+Node: Periodic transactions45251
+Ref: #periodic-transactions45433
+Node: Forecasting with periodic transactions46644
+Ref: #forecasting-with-periodic-transactions46887
+Node: Budgeting with periodic transactions48574
+Ref: #budgeting-with-periodic-transactions48813
+Node: Transaction Modifiers49272
+Ref: #transaction-modifiers49435
+Node: EDITOR SUPPORT50691
+Ref: #editor-support50809
 
 End Tag Table
diff --git a/embeddedfiles/hledger_journal.txt b/embeddedfiles/hledger_journal.txt
--- a/embeddedfiles/hledger_journal.txt
+++ b/embeddedfiles/hledger_journal.txt
@@ -705,14 +705,15 @@
               include path/to/file.journal
 
        If  the path does not begin with a slash, it is relative to the current
-       file.  Glob patterns (*) are not currently supported.
+       file.  The include file path may contain  common  glob  patterns  (e.g.
+       *).
 
-       The include directive can only  be  used  in  journal  files.   It  can
+       The  include  directive  can  only  be  used  in journal files.  It can
        include journal, timeclock or timedot files, but not CSV files.
 
    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
@@ -732,8 +733,8 @@
                 assets
 
    Declaring commodities
-       The  commodity  directive declares commodities which may be used in the
-       journal (though currently we do not enforce this).  It may  be  written
+       The commodity directive declares commodities which may be used  in  the
+       journal  (though  currently we do not enforce this).  It may be written
        on a single line, like this:
 
               ; commodity EXAMPLEAMOUNT
@@ -743,8 +744,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
@@ -756,19 +757,19 @@
               commodity INR
                 format INR 9,99,99,999.00
 
-       Commodity  directives  have  a second purpose: they define the standard
+       Commodity directives have a second purpose: they  define  the  standard
        display format for amounts in the commodity.  Normally the display for-
-       mat  is  inferred  from journal entries, but this can be unpredictable;
-       declaring it with a commodity  directive  overrides  this  and  removes
-       ambiguity.   Towards  this  end,  amounts  in commodity directives must
-       always be written with a decimal point (a period or comma, followed  by
+       mat is inferred from journal entries, but this  can  be  unpredictable;
+       declaring  it  with  a  commodity  directive overrides this and removes
+       ambiguity.  Towards this end,  amounts  in  commodity  directives  must
+       always  be written with a decimal point (a period or comma, followed by
        0 or more decimal digits).
 
    Default commodity
-       The  D  directive  sets a default commodity (and display format), to be
+       The D directive sets a default commodity (and display  format),  to  be
        used for amounts without a commodity symbol (ie, plain numbers).  (Note
-       this  differs from Ledger's default commodity directive.) The commodity
-       and display format will be applied  to  all  subsequent  commodity-less
+       this differs from Ledger's default commodity directive.) The  commodity
+       and  display  format  will  be applied to all subsequent commodity-less
        amounts, or until the next D directive.
 
               # commodity-less amounts should be treated as dollars
@@ -783,9 +784,9 @@
        a decimal point.
 
    Market prices
-       The P directive declares a market price,  which  is  an  exchange  rate
+       The  P  directive  declares  a  market price, which is an exchange rate
        between two commodities on a certain date.  (In Ledger, they are called
-       "historical prices".) These are often obtained from a  stock  exchange,
+       "historical  prices".)  These are often obtained from a stock exchange,
        cryptocurrency exchange, or the foreign exchange market.
 
        Here is the format:
@@ -796,67 +797,84 @@
 
        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  $1.35
               P 2010/1/1  $1.40
 
-       The  -V/--value flag can be used to convert reported amounts to another
+       The -V/--value flag can be used to convert reported amounts to  another
        commodity using these prices.
 
    Declaring accounts
-       The account directive predeclares account names.  The simplest form  is
+       The  account directive predeclares account names.  The simplest form is
        account ACCTNAME, eg:
 
               account assets:bank:checking
 
-       Currently  this  mainly  helps  with  account name autocompletion in eg
+       Currently this mainly helps with  account  name  autocompletion  in  eg
        hledger add, hledger-iadd, hledger-web, and ledger-mode.
        In future it will also help detect misspelled accounts.
 
-       Account names can be followed by a numeric account code:
+       An account directive can also have indented subdirectives following it,
+       which are currently ignored.  Here is the full syntax:
 
-              account assets                  1000
-              account assets:bank:checking    1110
-              account liabilities             2000
-              account revenues                4000
-              account expenses                6000
+              ; account ACCTNAME
+              ;   [OPTIONALSUBDIRECTIVES]
 
-       This affects how accounts are sorted in account  and  balance  reports:
-       accounts  with  codes  are listed before accounts without codes, and in
-       increasing code order (instead of listing all accounts alphabetically).
-       Warning,  this  feature  is incomplete; account codes do not yet affect
-       sort order in
+              account assets:bank:checking
+                a comment
+                some-tag:12345
 
-       o the accounts command
+   Account display order
+       Account directives have another purpose: they set the  order  in  which
+       accounts are displayed, in hledger reports, hledger-ui accounts screen,
+       hledger-web sidebar etc.  For example, say  you  have  these  top-level
+       accounts:
 
-       o the balance command's single-column mode
+              $ accounts -1
+              assets
+              equity
+              expenses
+              liabilities
+              misc
+              other
+              revenues
 
-       o flat mode balance reports (to work around this, declare account codes
-         on the subaccounts as well).
+       By  default,  they are displayed in alphabetical order.  But if you add
+       the following account directives to the journal:
 
-       o hledger-web's sidebar
+              account assets
+              account liabilities
+              account equity
+              account revenues
+              account expenses
 
-       Account  codes should be all numeric digits, unique, and separated from
-       the account name by at least two spaces (since account names  may  con-
-       tain  single  spaces).   By convention, often the first digit indicates
-       the type of account, as in this numbering scheme and the example above.
-       In future, we might use this to recognize account types.
+       the display order changes to:
 
-       An account directive can also have indented subdirectives following it,
-       which are currently ignored.  Here is the full syntax:
+              $ accounts -1
+              assets
+              liabilities
+              equity
+              revenues
+              expenses
+              misc
+              other
 
-              ; account ACCTNAME  [OPTIONALCODE]
-              ;   [OPTIONALSUBDIRECTIVES]
+       Ie, declared accounts first, in the order they were declared,  followed
+       by any undeclared accounts in alphabetic order.
 
-              account assets:bank:checking   1110
-                a comment
-                some-tag:12345
+       Note  that  sorting  is  done at each level of the account tree (within
+       each group of sibling accounts under the same parent).  This directive:
 
+              account other:zoo
+
+       would  influence the position of zoo among other's subaccounts, but not
+       the position of other among the top-level accounts.
+
    Rewriting accounts
        You can define account alias rules which rewrite your account names, or
        parts of them, before generating reports.  This can be useful for:
@@ -976,7 +994,7 @@
 
        A periodic transaction rule looks like a normal journal entry, with the
        date replaced by a tilde (~) followed by a period expression (mnemonic:
-       ~ looks like a repeating sine wave):
+       ~ looks like a recurring sine wave.):
 
               ~ monthly
                   expenses:rent          $2000
@@ -1003,56 +1021,71 @@
        normal transactions, but with an extra tag named recur, whose value  is
        the generating period expression.
 
-       Forecast transactions begin on or after the day after the latest normal
-       (non-periodic) transaction in the journal, or today if there are  none.
+       Forecast  transactions  start  on  the first occurrence, and end on the
+       last occurrence, of their interval within  the  forecast  period.   The
+       forecast period:
 
-       They  end  on  or  before the report end date if specified, or 180 days
-       from today if unspecified.
+       o begins on the later of
 
-       Forecasting can be useful for estimating balances into the future,  and
-       experimenting  with  different  scenarios.   Note  the start date logic
+         o the report start date if specified with -b/-p/date:
+
+         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  180
+         days from today.
+
+       where  "today"  means  the current date at report time.  The "later of"
+       rule ensures that forecast transactions do not overlap normal  transac-
+       tions in time; they will begin only after normal transactions end.
+
+       Forecasting  can be useful for estimating balances into the future, and
+       experimenting with different scenarios.   Note  the  start  date  logic
        means that forecasted transactions are automatically replaced by normal
        transactions as you add those.
 
        Forecasting can also help with data entry: describe most of your trans-
-       actions with periodic rules, and every so  often  copy  the  output  of
+       actions  with  periodic  rules,  and  every so often copy the output of
        print --forecast to the journal.
 
        You can generate one-time transactions too: just write a period expres-
-       sion specifying a date with no report interval.  (You could also  write
-       a  normal  transaction  with  a future date, but remember this disables
+       sion  specifying a date with no report interval.  (You could also write
+       a normal transaction with a future date,  but  remember  this  disables
        forecast transactions on previous dates.)
 
    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 Cookbook: Budgeting
+       For more details, see: balance: Budget report and  Cookbook:  Budgeting
        and Forecasting.
 
-   Automated postings
-       Automated posting rules describe extra postings that should be added to
-       certain transactions at report time, when the --auto flag is used.
 
-       An automated posting rule looks like a normal journal entry, except the
-       first line is an equal sign (=) followed by a query (mnemonic: =  looks
-       like posting lines):
+   Transaction Modifiers
+       Transaction  modifier  rules  describe  changes  that should be applied
+       automatically to certain transactions.  Currently,  this  means  adding
+       extra postings (also known as "automated postings").  Transaction modi-
+       fiers are enabled by the --auto flag.
 
+       A transaction modifier rule looks a bit like a  normal  journal  entry,
+       except  the  first  line  is  an  equal  sign  (=)  followed by a query
+       (mnemonic: = suggests matching something.):
+
               = expenses:gifts
                   budget:gifts  *-1
                   assets:budget  *1
 
-       The  posting  amounts can be of the form *N, which means "the amount of
-       the matched transaction's first posting, multiplied by  N".   They  can
+       The posting amounts can be of the form *N, which means "the  amount  of
+       the  matched  transaction's  first posting, multiplied by N".  They can
        also be ordinary fixed amounts.  Fixed amounts with no commodity symbol
-       will be given the same commodity as  the  matched  transaction's  first
+       will  be  given  the  same commodity as the matched transaction's first
        posting.
 
-       This  example adds a corresponding (unbalanced) budget posting to every
+       This example adds a corresponding (unbalanced) budget posting to  every
        transaction involving the expenses:gifts account:
 
               = expenses:gifts
@@ -1068,16 +1101,16 @@
                   (budget:gifts)            $-20
                   assets
 
-       Like postings recorded  by  hand,  automated  postings  participate  in
+       Like  postings  recorded  by  hand,  automated  postings participate in
        transaction balancing, missing amount inference and balance assertions.
 
 EDITOR SUPPORT
        Add-on modes exist for various text editors, to make working with jour-
-       nal  files  easier.   They add colour, navigation aids and helpful com-
-       mands.  For hledger users who  edit  the  journal  file  directly  (the
+       nal files easier.  They add colour, navigation aids  and  helpful  com-
+       mands.   For  hledger  users  who  edit  the journal file directly (the
        majority), using one of these modes is quite recommended.
 
-       These  were  written  with  Ledger  in mind, but also work with hledger
+       These were written with Ledger in mind,  but  also  work  with  hledger
        files:
 
 
@@ -1090,14 +1123,13 @@
        Textmate       https://github.com/ledger/ledger/wiki/Using-TextMate-2
        Text   Wran-   https://github.com/ledger/ledger/wiki/Edit-
        gler           ing-Ledger-files-with-TextWrangler
-
        Visual  Stu-   https://marketplace.visualstudio.com/items?item-
        dio Code       Name=mark-hansen.hledger-vscode
 
 
 
 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)
 
 
@@ -1111,7 +1143,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)
 
@@ -1119,4 +1151,4 @@
 
 
 
-hledger 1.9.99                     June 2018                hledger_journal(5)
+hledger 1.10.99                 September 2018              hledger_journal(5)
diff --git a/embeddedfiles/hledger_timeclock.5 b/embeddedfiles/hledger_timeclock.5
--- a/embeddedfiles/hledger_timeclock.5
+++ b/embeddedfiles/hledger_timeclock.5
@@ -1,5 +1,5 @@
 
-.TH "hledger_timeclock" "5" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger_timeclock" "5" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
diff --git a/embeddedfiles/hledger_timeclock.info b/embeddedfiles/hledger_timeclock.info
--- a/embeddedfiles/hledger_timeclock.info
+++ b/embeddedfiles/hledger_timeclock.info
@@ -4,8 +4,8 @@
 
 File: hledger_timeclock.info,  Node: Top,  Up: (dir)
 
-hledger_timeclock(5) hledger 1.9.99
-***********************************
+hledger_timeclock(5) hledger 1.10.99
+************************************
 
 hledger can read timeclock files.  As with Ledger, these are (a subset
 of) timeclock.el's format, containing clock-in and clock-out entries as
diff --git a/embeddedfiles/hledger_timeclock.txt b/embeddedfiles/hledger_timeclock.txt
--- a/embeddedfiles/hledger_timeclock.txt
+++ b/embeddedfiles/hledger_timeclock.txt
@@ -77,4 +77,4 @@
 
 
 
-hledger 1.9.99                     June 2018              hledger_timeclock(5)
+hledger 1.10.99                 September 2018            hledger_timeclock(5)
diff --git a/embeddedfiles/hledger_timedot.5 b/embeddedfiles/hledger_timedot.5
--- a/embeddedfiles/hledger_timedot.5
+++ b/embeddedfiles/hledger_timedot.5
@@ -1,5 +1,5 @@
 
-.TH "hledger_timedot" "5" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger_timedot" "5" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
diff --git a/embeddedfiles/hledger_timedot.info b/embeddedfiles/hledger_timedot.info
--- a/embeddedfiles/hledger_timedot.info
+++ b/embeddedfiles/hledger_timedot.info
@@ -4,8 +4,8 @@
 
 File: hledger_timedot.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir)
 
-hledger_timedot(5) hledger 1.9.99
-*********************************
+hledger_timedot(5) hledger 1.10.99
+**********************************
 
 Timedot is a plain text format for logging dated, categorised quantities
 (of time, usually), supported by hledger.  It is convenient for
@@ -110,7 +110,7 @@
 
 Tag Table:
 Node: Top76
-Node: FILE FORMAT811
-Ref: #file-format912
+Node: FILE FORMAT813
+Ref: #file-format914
 
 End Tag Table
diff --git a/embeddedfiles/hledger_timedot.txt b/embeddedfiles/hledger_timedot.txt
--- a/embeddedfiles/hledger_timedot.txt
+++ b/embeddedfiles/hledger_timedot.txt
@@ -124,4 +124,4 @@
 
 
 
-hledger 1.9.99                     June 2018                hledger_timedot(5)
+hledger 1.10.99                 September 2018              hledger_timedot(5)
diff --git a/hledger.1 b/hledger.1
--- a/hledger.1
+++ b/hledger.1
@@ -1,6 +1,6 @@
 .\"t
 
-.TH "hledger" "1" "June 2018" "hledger 1.9.99" "hledger User Manuals"
+.TH "hledger" "1" "September 2018" "hledger 1.10.99" "hledger User Manuals"
 
 
 
@@ -188,6 +188,11 @@
 .RS
 .RE
 .TP
+.B \f[C]\-\-separator=CHAR\f[]
+Field separator to expect when reading CSV (default: `,')
+.RS
+.RE
+.TP
 .B \f[C]\-\-alias=OLD=NEW\f[]
 rename accounts named OLD to NEW
 .RS
@@ -2241,6 +2246,11 @@
 This was formerly called \[lq]equity\[rq], as in Ledger, and that alias
 is also accepted.
 See close \[en]help for more.
+.SS files
+.PP
+List all files included in the journal.
+With a REGEX argument, only file names matching the regular expression
+(case sensitive) are shown.
 .SS help
 .PP
 Show any of the hledger manuals.
@@ -2426,7 +2436,12 @@
 selection.
 .SS prices
 .PP
-Print all market prices from the journal.
+Print market price directives from the journal.
+With \[en]costs, also print synthetic market prices based on transaction
+prices.
+With \[en]inverted\-costs, also print inverse prices based on
+transaction prices.
+Prices (and postings providing prices) can be filtered by a query.
 .SS print
 .PP
 Show transactions from the journal.
@@ -2759,6 +2774,11 @@
 .SS rewrite
 .PP
 Print all transactions, adding custom postings to the matched ones.
+.SS roi
+.PP
+Shows time\-weighted (TWR) and money\-weighted (IRR) rate of return on
+your investments.
+See \f[C]roi\ \-\-help\f[] for more.
 .SS stats
 .PP
 Show some journal statistics.
@@ -2801,20 +2821,22 @@
 .SS test
 .PP
 Run built\-in unit tests.
-.IP
-.nf
-\f[C]
-$\ hledger\ test
-Cases:\ 74\ \ Tried:\ 74\ \ Errors:\ 0\ \ Failures:\ 0
-\f[]
-.fi
 .PP
-This command runs hledger's built\-in unit tests and displays a quick
-report.
-With a regular expression argument, it selects only tests with matching
-names.
-It's mainly used in development, but it's also nice to be able to check
-your hledger executable for smoke at any time.
+Prints test names and their results on stdout.
+If any test fails or gives an error, the exit code will be non\-zero.
+.PP
+Test names include a group prefix.
+If a (exact, case sensitive) group prefix, or a full test name is
+provided as the first argument, only that group or test is run.
+.PP
+If a numeric second argument is provided, it will set the randomness
+seed, for repeatable results from tests using randomness (currently none
+of them).
+.PP
+This is mainly used by developers, but it's nice to be able to
+sanity\-check your installed hledger executable at any time.
+All tests are expected to pass \- if you ever see otherwise, something
+has gone wrong, please report a bug!
 .SH ADD\-ON COMMANDS
 .PP
 hledger also searches for external add\-on commands, and will include
diff --git a/hledger.cabal b/hledger.cabal
--- a/hledger.cabal
+++ b/hledger.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 9d4dec437459d541e707fa97a836aa8b4878e685d84738bcb462c370387ad83a
+-- hash: a53ed723ef2c43c6425e4bf2d40ae7a37b9816dcdbd49795a7a7972b4b4ca203
 
 name:           hledger
-version:        1.10
+version:        1.11
 synopsis:       Command-line interface for the hledger accounting tool
 description:    This is hledger's command-line interface.
                 Its basic function is to read a plain text file describing
@@ -25,7 +25,7 @@
 maintainer:     Simon Michael <simon@joyful.com>
 license:        GPL-3
 license-file:   LICENSE
-tested-with:    GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.1
+tested-with:    GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
 build-type:     Simple
 cabal-version:  >= 1.10
 extra-source-files:
@@ -95,6 +95,7 @@
       Hledger.Cli.Commands.Checkdupes
       Hledger.Cli.Commands.Close
       Hledger.Cli.Commands.Help
+      Hledger.Cli.Commands.Files
       Hledger.Cli.Commands.Import
       Hledger.Cli.Commands.Incomestatement
       Hledger.Cli.Commands.Prices
@@ -103,34 +104,34 @@
       Hledger.Cli.Commands.Register
       Hledger.Cli.Commands.Registermatch
       Hledger.Cli.Commands.Rewrite
+      Hledger.Cli.Commands.Roi
       Hledger.Cli.Commands.Stats
       Hledger.Cli.Commands.Tags
       Hledger.Cli.CompoundBalanceCommand
   other-modules:
       Paths_hledger
   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans -optP-Wno-nonportable-include-path
-  cpp-options: -DVERSION="1.10"
+  cpp-options: -DVERSION="1.11"
   build-depends:
       Decimal
     , Diff
-    , HUnit
     , ansi-terminal >=0.6.2.3
     , base >=4.8 && <4.12
     , base-compat-batteries >=0.10.1 && <0.11
     , bytestring
     , cmdargs >=0.10
     , containers
-    , csv
     , data-default >=0.5
     , directory
+    , easytest
     , file-embed >=0.0.10
     , filepath
     , hashable >=1.2.4
     , haskeline >=0.6
     , here
-    , hledger-lib >=1.10 && <1.11
+    , hledger-lib >=1.11 && <1.12
     , lucid
-    , megaparsec >=6.4.1
+    , megaparsec >=6.4.1 && <7
     , mtl
     , mtl-compat
     , old-time
@@ -141,6 +142,7 @@
     , safe >=0.2
     , shakespeare >=2.0.2.2
     , split >=0.1
+    , statistics
     , tabular >=0.2
     , temporary
     , text >=0.11
@@ -162,26 +164,25 @@
   hs-source-dirs:
       app
   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans -optP-Wno-nonportable-include-path
-  cpp-options: -DVERSION="1.10"
+  cpp-options: -DVERSION="1.11"
   build-depends:
       Decimal
-    , HUnit
     , ansi-terminal >=0.6.2.3
     , base >=4.8 && <4.12
     , base-compat-batteries >=0.10.1 && <0.11
     , bytestring
     , cmdargs >=0.10
     , containers
-    , csv
     , data-default >=0.5
     , directory
+    , easytest
     , file-embed >=0.0.10
     , filepath
     , haskeline >=0.6
     , here
     , hledger
-    , hledger-lib >=1.10 && <1.11
-    , megaparsec >=6.4.1
+    , hledger-lib >=1.11 && <1.12
+    , megaparsec >=6.4.1 && <7
     , mtl
     , mtl-compat
     , old-time
@@ -192,6 +193,7 @@
     , safe >=0.2
     , shakespeare >=2.0.2.2
     , split >=0.1
+    , statistics
     , tabular >=0.2
     , temporary
     , text >=0.11
@@ -216,26 +218,25 @@
   hs-source-dirs:
       test
   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans -optP-Wno-nonportable-include-path
-  cpp-options: -DVERSION="1.10"
+  cpp-options: -DVERSION="1.11"
   build-depends:
       Decimal
-    , HUnit
     , ansi-terminal >=0.6.2.3
     , base >=4.8 && <4.12
     , base-compat-batteries >=0.10.1 && <0.11
     , bytestring
     , cmdargs >=0.10
     , containers
-    , csv
     , data-default >=0.5
     , directory
+    , easytest
     , file-embed >=0.0.10
     , filepath
     , haskeline >=0.6
     , here
     , hledger
-    , hledger-lib >=1.10 && <1.11
-    , megaparsec >=6.4.1
+    , hledger-lib >=1.11 && <1.12
+    , megaparsec >=6.4.1 && <7
     , mtl
     , mtl-compat
     , old-time
@@ -246,6 +247,7 @@
     , safe >=0.2
     , shakespeare >=2.0.2.2
     , split >=0.1
+    , statistics
     , tabular >=0.2
     , temporary
     , test-framework
@@ -272,7 +274,6 @@
   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans -optP-Wno-nonportable-include-path
   build-depends:
       Decimal
-    , HUnit
     , ansi-terminal >=0.6.2.3
     , base >=4.8 && <4.12
     , base-compat-batteries >=0.10.1 && <0.11
@@ -280,17 +281,17 @@
     , cmdargs >=0.10
     , containers
     , criterion
-    , csv
     , data-default >=0.5
     , directory
+    , easytest
     , file-embed >=0.0.10
     , filepath
     , haskeline >=0.6
     , here
     , hledger
-    , hledger-lib >=1.10 && <1.11
+    , hledger-lib >=1.11 && <1.12
     , html
-    , megaparsec >=6.4.1
+    , megaparsec >=6.4.1 && <7
     , mtl
     , mtl-compat
     , old-time
@@ -301,6 +302,7 @@
     , safe >=0.2
     , shakespeare >=2.0.2.2
     , split >=0.1
+    , statistics
     , tabular >=0.2
     , temporary
     , text >=0.11
diff --git a/hledger.info b/hledger.info
--- a/hledger.info
+++ b/hledger.info
@@ -3,8 +3,8 @@
 
 File: hledger.info,  Node: Top,  Next: EXAMPLES,  Up: (dir)
 
-hledger(1) hledger 1.9.99
-*************************
+hledger(1) hledger 1.10.99
+**************************
 
 This is hledger's command-line interface (there are also curses and web
 interfaces).  Its basic function is to read a plain text file describing
@@ -164,6 +164,9 @@
 '--rules-file=RULESFILE'
 
      Conversion rules file to use when reading CSV (default: FILE.rules)
+'--separator=CHAR'
+
+     Field separator to expect when reading CSV (default: ',')
 '--alias=OLD=NEW'
 
      rename accounts named OLD to NEW
@@ -909,6 +912,7 @@
 * check-dates::
 * check-dupes::
 * close::
+* files::
 * help::
 * import::
 * incomestatement::
@@ -918,6 +922,7 @@
 * register::
 * register-match::
 * rewrite::
+* roi::
 * stats::
 * tags::
 * test::
@@ -1754,7 +1759,7 @@
 example: http://stefanorodighiero.net/software/hledger-dupes.html
 
 
-File: hledger.info,  Node: close,  Next: help,  Prev: check-dupes,  Up: COMMANDS
+File: hledger.info,  Node: close,  Next: files,  Prev: check-dupes,  Up: COMMANDS
 
 4.10 close
 ==========
@@ -1766,9 +1771,18 @@
 alias is also accepted.  See close -help for more.
 
 
-File: hledger.info,  Node: help,  Next: import,  Prev: close,  Up: COMMANDS
+File: hledger.info,  Node: files,  Next: help,  Prev: close,  Up: COMMANDS
 
-4.11 help
+4.11 files
+==========
+
+List all files included in the journal.  With a REGEX argument, only
+file names matching the regular expression (case sensitive) are shown.
+
+
+File: hledger.info,  Node: help,  Next: import,  Prev: files,  Up: COMMANDS
+
+4.12 help
 =========
 
 Show any of the hledger manuals.
@@ -1805,7 +1819,7 @@
 
 File: hledger.info,  Node: import,  Next: incomestatement,  Prev: help,  Up: COMMANDS
 
-4.12 import
+4.13 import
 ===========
 
 Read new transactions added to each FILE since last run, and add them to
@@ -1831,7 +1845,7 @@
 
 File: hledger.info,  Node: incomestatement,  Next: prices,  Prev: import,  Up: COMMANDS
 
-4.13 incomestatement
+4.14 incomestatement
 ====================
 
 This command displays a simple income statement, showing revenues and
@@ -1918,15 +1932,18 @@
 
 File: hledger.info,  Node: prices,  Next: print,  Prev: incomestatement,  Up: COMMANDS
 
-4.14 prices
+4.15 prices
 ===========
 
-Print all market prices from the journal.
+Print market price directives from the journal.  With -costs, also print
+synthetic market prices based on transaction prices.  With
+-inverted-costs, also print inverse prices based on transaction prices.
+Prices (and postings providing prices) can be filtered by a query.
 
 
 File: hledger.info,  Node: print,  Next: print-unique,  Prev: prices,  Up: COMMANDS
 
-4.15 print
+4.16 print
 ==========
 
 Show transactions from the journal.  Aliases: p, txns.
@@ -2043,7 +2060,7 @@
 
 File: hledger.info,  Node: print-unique,  Next: register,  Prev: print,  Up: COMMANDS
 
-4.16 print-unique
+4.17 print-unique
 =================
 
 Print transactions which do not reuse an already-seen description.
@@ -2051,7 +2068,7 @@
 
 File: hledger.info,  Node: register,  Next: register-match,  Prev: print-unique,  Up: COMMANDS
 
-4.17 register
+4.18 register
 =============
 
 Show postings and their running total.  Aliases: r, reg.
@@ -2156,7 +2173,7 @@
 
 File: hledger.info,  Node: Custom register output,  Up: register
 
-4.17.1 Custom register output
+4.18.1 Custom register output
 -----------------------------
 
 register uses the full terminal width by default, except on windows.
@@ -2187,7 +2204,7 @@
 
 File: hledger.info,  Node: register-match,  Next: rewrite,  Prev: register,  Up: COMMANDS
 
-4.18 register-match
+4.19 register-match
 ===================
 
 Print the one posting whose transaction description is closest to DESC,
@@ -2195,17 +2212,26 @@
 already-seen transactions when importing.
 
 
-File: hledger.info,  Node: rewrite,  Next: stats,  Prev: register-match,  Up: COMMANDS
+File: hledger.info,  Node: rewrite,  Next: roi,  Prev: register-match,  Up: COMMANDS
 
-4.19 rewrite
+4.20 rewrite
 ============
 
 Print all transactions, adding custom postings to the matched ones.
 
 
-File: hledger.info,  Node: stats,  Next: tags,  Prev: rewrite,  Up: COMMANDS
+File: hledger.info,  Node: roi,  Next: stats,  Prev: rewrite,  Up: COMMANDS
 
-4.20 stats
+4.21 roi
+========
+
+Shows time-weighted (TWR) and money-weighted (IRR) rate of return on
+your investments.  See 'roi --help' for more.
+
+
+File: hledger.info,  Node: stats,  Next: tags,  Prev: roi,  Up: COMMANDS
+
+4.22 stats
 ==========
 
 Show some journal statistics.
@@ -2237,7 +2263,7 @@
 
 File: hledger.info,  Node: tags,  Next: test,  Prev: stats,  Up: COMMANDS
 
-4.21 tags
+4.23 tags
 =========
 
 List all the tag names used in the journal.  With a TAGREGEX argument,
@@ -2248,19 +2274,27 @@
 
 File: hledger.info,  Node: test,  Prev: tags,  Up: COMMANDS
 
-4.22 test
+4.24 test
 =========
 
 Run built-in unit tests.
 
-$ hledger test
-Cases: 74  Tried: 74  Errors: 0  Failures: 0
+   Prints test names and their results on stdout.  If any test fails or
+gives an error, the exit code will be non-zero.
 
-   This command runs hledger's built-in unit tests and displays a quick
-report.  With a regular expression argument, it selects only tests with
-matching names.  It's mainly used in development, but it's also nice to
-be able to check your hledger executable for smoke at any time.
+   Test names include a group prefix.  If a (exact, case sensitive)
+group prefix, or a full test name is provided as the first argument,
+only that group or test is run.
 
+   If a numeric second argument is provided, it will set the randomness
+seed, for repeatable results from tests using randomness (currently none
+of them).
+
+   This is mainly used by developers, but it's nice to be able to
+sanity-check your installed hledger executable at any time.  All tests
+are expected to pass - if you ever see otherwise, something has gone
+wrong, please report a bug!
+
 
 File: hledger.info,  Node: ADD-ON COMMANDS,  Prev: COMMANDS,  Up: Top
 
@@ -2433,138 +2467,142 @@
 
 Tag Table:
 Node: Top68
-Node: EXAMPLES1888
-Ref: #examples1988
-Node: OPTIONS3634
-Ref: #options3736
-Node: General options4101
-Ref: #general-options4226
-Node: Command options6825
-Ref: #command-options6976
-Node: Command arguments7374
-Ref: #command-arguments7528
-Node: Argument files7649
-Ref: #argument-files7800
-Node: Special characters8066
-Ref: #special-characters8219
-Node: Input files9638
-Ref: #input-files9774
-Node: Smart dates11744
-Ref: #smart-dates11885
-Node: Report start & end date13291
-Ref: #report-start-end-date13461
-Node: Report intervals14526
-Ref: #report-intervals14689
-Node: Period expressions15090
-Ref: #period-expressions15250
-Node: Depth limiting19207
-Ref: #depth-limiting19351
-Node: Pivoting19693
-Ref: #pivoting19811
-Node: Cost21487
-Ref: #cost21595
-Node: Market value21713
-Ref: #market-value21848
-Node: Combining -B and -V23214
-Ref: #combining--b-and--v23377
-Node: Output destination23524
-Ref: #output-destination23686
-Node: Output format23969
-Ref: #output-format24121
-Node: Regular expressions24506
-Ref: #regular-expressions24643
-Node: QUERIES26004
-Ref: #queries26106
-Node: COMMANDS30068
-Ref: #commands30180
-Node: accounts31162
-Ref: #accounts31260
-Node: activity32506
-Ref: #activity32616
-Node: add32976
-Ref: #add33075
-Node: balance35736
-Ref: #balance35847
-Node: Classic balance report38930
-Ref: #classic-balance-report39103
-Node: Customising the classic balance report40472
-Ref: #customising-the-classic-balance-report40700
-Node: Colour support42774
-Ref: #colour-support42941
-Node: Flat mode43114
-Ref: #flat-mode43262
-Node: Depth limited balance reports43675
-Ref: #depth-limited-balance-reports43875
-Node: Multicolumn balance report44331
-Ref: #multicolumn-balance-report44529
-Node: Budget report49709
-Ref: #budget-report49852
-Ref: #output-format-152886
-Node: balancesheet52964
-Ref: #balancesheet53100
-Node: balancesheetequity55411
-Ref: #balancesheetequity55560
-Node: cashflow56097
-Ref: #cashflow56225
-Node: check-dates58348
-Ref: #check-dates58475
-Node: check-dupes58592
-Ref: #check-dupes58716
-Node: close58853
-Ref: #close58960
-Node: help59290
-Ref: #help59390
-Node: import60464
-Ref: #import60578
-Node: incomestatement61308
-Ref: #incomestatement61442
-Node: prices63846
-Ref: #prices63961
-Node: print64004
-Ref: #print64114
-Node: print-unique69008
-Ref: #print-unique69134
-Node: register69202
-Ref: #register69329
-Node: Custom register output73830
-Ref: #custom-register-output73959
-Node: register-match75189
-Ref: #register-match75323
-Node: rewrite75506
-Ref: #rewrite75623
-Node: stats75692
-Ref: #stats75795
-Node: tags76665
-Ref: #tags76763
-Node: test76999
-Ref: #test77083
-Node: ADD-ON COMMANDS77451
-Ref: #add-on-commands77561
-Node: Official add-ons78848
-Ref: #official-add-ons78988
-Node: api79075
-Ref: #api79164
-Node: ui79216
-Ref: #ui79315
-Node: web79373
-Ref: #web79462
-Node: Third party add-ons79508
-Ref: #third-party-add-ons79683
-Node: diff79818
-Ref: #diff79915
-Node: iadd80014
-Ref: #iadd80128
-Node: interest80211
-Ref: #interest80332
-Node: irr80427
-Ref: #irr80525
-Node: Experimental add-ons80603
-Ref: #experimental-add-ons80755
-Node: autosync81035
-Ref: #autosync81146
-Node: chart81385
-Ref: #chart81504
-Node: check81575
-Ref: #check81677
+Node: EXAMPLES1890
+Ref: #examples1990
+Node: OPTIONS3636
+Ref: #options3738
+Node: General options4103
+Ref: #general-options4228
+Node: Command options6910
+Ref: #command-options7061
+Node: Command arguments7459
+Ref: #command-arguments7613
+Node: Argument files7734
+Ref: #argument-files7885
+Node: Special characters8151
+Ref: #special-characters8304
+Node: Input files9723
+Ref: #input-files9859
+Node: Smart dates11829
+Ref: #smart-dates11970
+Node: Report start & end date13376
+Ref: #report-start-end-date13546
+Node: Report intervals14611
+Ref: #report-intervals14774
+Node: Period expressions15175
+Ref: #period-expressions15335
+Node: Depth limiting19292
+Ref: #depth-limiting19436
+Node: Pivoting19778
+Ref: #pivoting19896
+Node: Cost21572
+Ref: #cost21680
+Node: Market value21798
+Ref: #market-value21933
+Node: Combining -B and -V23299
+Ref: #combining--b-and--v23462
+Node: Output destination23609
+Ref: #output-destination23771
+Node: Output format24054
+Ref: #output-format24206
+Node: Regular expressions24591
+Ref: #regular-expressions24728
+Node: QUERIES26089
+Ref: #queries26191
+Node: COMMANDS30153
+Ref: #commands30265
+Node: accounts31265
+Ref: #accounts31363
+Node: activity32609
+Ref: #activity32719
+Node: add33079
+Ref: #add33178
+Node: balance35839
+Ref: #balance35950
+Node: Classic balance report39033
+Ref: #classic-balance-report39206
+Node: Customising the classic balance report40575
+Ref: #customising-the-classic-balance-report40803
+Node: Colour support42877
+Ref: #colour-support43044
+Node: Flat mode43217
+Ref: #flat-mode43365
+Node: Depth limited balance reports43778
+Ref: #depth-limited-balance-reports43978
+Node: Multicolumn balance report44434
+Ref: #multicolumn-balance-report44632
+Node: Budget report49812
+Ref: #budget-report49955
+Ref: #output-format-152989
+Node: balancesheet53067
+Ref: #balancesheet53203
+Node: balancesheetequity55514
+Ref: #balancesheetequity55663
+Node: cashflow56200
+Ref: #cashflow56328
+Node: check-dates58451
+Ref: #check-dates58578
+Node: check-dupes58695
+Ref: #check-dupes58819
+Node: close58956
+Ref: #close59064
+Node: files59394
+Ref: #files59495
+Node: help59636
+Ref: #help59736
+Node: import60810
+Ref: #import60924
+Node: incomestatement61654
+Ref: #incomestatement61788
+Node: prices64192
+Ref: #prices64307
+Node: print64579
+Ref: #print64689
+Node: print-unique69583
+Ref: #print-unique69709
+Node: register69777
+Ref: #register69904
+Node: Custom register output74405
+Ref: #custom-register-output74534
+Node: register-match75764
+Ref: #register-match75898
+Node: rewrite76081
+Ref: #rewrite76196
+Node: roi76265
+Ref: #roi76363
+Node: stats76479
+Ref: #stats76578
+Node: tags77448
+Ref: #tags77546
+Node: test77782
+Ref: #test77866
+Node: ADD-ON COMMANDS78574
+Ref: #add-on-commands78684
+Node: Official add-ons79971
+Ref: #official-add-ons80111
+Node: api80198
+Ref: #api80287
+Node: ui80339
+Ref: #ui80438
+Node: web80496
+Ref: #web80585
+Node: Third party add-ons80631
+Ref: #third-party-add-ons80806
+Node: diff80941
+Ref: #diff81038
+Node: iadd81137
+Ref: #iadd81251
+Node: interest81334
+Ref: #interest81455
+Node: irr81550
+Ref: #irr81648
+Node: Experimental add-ons81726
+Ref: #experimental-add-ons81878
+Node: autosync82158
+Ref: #autosync82269
+Node: chart82508
+Ref: #chart82627
+Node: check82698
+Ref: #check82800
 
 End Tag Table
diff --git a/hledger.txt b/hledger.txt
--- a/hledger.txt
+++ b/hledger.txt
@@ -134,6 +134,9 @@
               Conversion  rules  file  to  use  when  reading  CSV   (default:
               FILE.rules)
 
+       --separator=CHAR
+              Field separator to expect when reading CSV (default: `,')
+
        --alias=OLD=NEW
               rename accounts named OLD to NEW
 
@@ -332,10 +335,6 @@
        Examples:
 
 
-
-
-
-
        2004/10/1,     2004-01-01,            exact  date, several sepa-
        2004.9.1                              rators allowed.   Year  is
                                              4+  digits, month is 1-12,
@@ -398,6 +397,7 @@
                          rent month
        -p thismonth      all  transactions  in  the
                          current month
+
        date:2016/3/17-   the   above   written   as
                          queries instead
        date:-12/1
@@ -531,6 +531,7 @@
        -p "every 2nd Monday"  -  period bound-
        aries will be on second Monday of  each
        month
+
        -p "every 11/05"  - yearly periods with
        boundaries on 5th of Nov
        -p "every 5th Nov" - same
@@ -1595,6 +1596,10 @@
        a  period.   This  was formerly called "equity", as in Ledger, and that
        alias is also accepted.  See close -help for more.
 
+   files
+       List all files included in the journal.  With a  REGEX  argument,  only
+       file  names matching the regular expression (case sensitive) are shown.
+
    help
        Show any of the hledger manuals.
 
@@ -1727,13 +1732,16 @@
        tion.
 
    prices
-       Print all market prices from the journal.
+       Print market price directives from  the  journal.   With  -costs,  also
+       print  synthetic  market  prices  based  on  transaction  prices.  With
+       -inverted-costs, also print inverse prices based on transaction prices.
+       Prices (and postings providing prices) can be filtered by a query.
 
    print
        Show transactions from the journal.  Aliases: p, txns.
 
        -m STR --match=STR
-              show the transaction whose description is most similar  to  STR,
+              show  the  transaction whose description is most similar to STR,
               and is most recent
 
        --new  show only newer-dated transactions added in each file since last
@@ -1746,7 +1754,7 @@
               select the output format.  Supported formats: txt, csv.
 
        -o FILE --output-file=FILE
-              write output to FILE.  A file  extension  matching  one  of  the
+              write  output  to  FILE.   A  file extension matching one of the
               above formats selects that format.
 
               $ hledger print
@@ -1777,39 +1785,39 @@
        it does not preserve directives or inter-transaction comments
 
        Normally, the journal entry's explicit or implicit amount style is pre-
-       served.   Ie when an amount is omitted in the journal, it will be omit-
-       ted in the output.  You can use the  -x/--explicit  flag  to  make  all
+       served.  Ie when an amount is omitted in the journal, it will be  omit-
+       ted  in  the  output.   You  can use the -x/--explicit flag to make all
        amounts explicit, which can be useful for troubleshooting or for making
        your journal more readable and robust against data entry errors.  Note,
-       -x  will  cause postings with a multi-commodity amount (these can arise
-       when a multi-commodity transaction has  an  implicit  amount)  will  be
-       split  into  multiple single-commodity postings, for valid journal out-
+       -x will cause postings with a multi-commodity amount (these  can  arise
+       when  a  multi-commodity  transaction  has  an implicit amount) will be
+       split into multiple single-commodity postings, for valid  journal  out-
        put.
 
-       With -B/--cost, amounts with transaction prices are converted  to  cost
+       With  -B/--cost,  amounts with transaction prices are converted to cost
        using that price.  This can be used for troubleshooting.
 
-       With  -m/--match and a STR argument, print will show at most one trans-
-       action: the one one whose description is most similar to  STR,  and  is
-       most  recent.  STR should contain at least two characters.  If there is
+       With -m/--match and a STR argument, print will show at most one  trans-
+       action:  the  one  one whose description is most similar to STR, and is
+       most recent.  STR should contain at least two characters.  If there  is
        no similar-enough match, no transaction will be shown.
 
        With --new, for each FILE being read, hledger reads (and writes) a spe-
-       cial  state  file  (.latest.FILE in the same directory), containing the
-       latest transaction date(s) that were seen  last  time  FILE  was  read.
-       When  this  file  is found, only transactions with newer dates (and new
-       transactions on the latest date)  are  printed.   This  is  useful  for
-       ignoring  already-seen  entries  in import data, such as downloaded CSV
+       cial state file (.latest.FILE in the same  directory),  containing  the
+       latest  transaction  date(s)  that  were  seen last time FILE was read.
+       When this file is found, only transactions with newer  dates  (and  new
+       transactions  on  the  latest  date)  are  printed.  This is useful for
+       ignoring already-seen entries in import data, such  as  downloaded  CSV
        files.  Eg:
 
               $ hledger -f bank1.csv print --new
               # shows transactions added since last print --new on this file
 
-       This assumes that transactions  added  to  FILE  always  have  same  or
-       increasing  dates,  and  that  transactions  on the same day do not get
+       This  assumes  that  transactions  added  to  FILE  always have same or
+       increasing dates, and that transactions on the  same  day  do  not  get
        reordered.  See also the import command.
 
-       This command also supports output destination and output format  selec-
+       This  command also supports output destination and output format selec-
        tion.  Here's an example of print's CSV output:
 
               $ hledger print -Ocsv
@@ -1826,20 +1834,20 @@
               "5","2008/12/31","","*","","pay off","","liabilities:debts","1","$","","1","",""
               "5","2008/12/31","","*","","pay off","","assets:bank:checking","-1","$","1","","",""
 
-       o There  is  one  CSV record per posting, with the parent transaction's
+       o There is one CSV record per posting, with  the  parent  transaction's
          fields repeated.
 
        o The "txnidx" (transaction index) field shows which postings belong to
-         the  same transaction.  (This number might change if transactions are
-         reordered within the file, files are parsed/included in  a  different
+         the same transaction.  (This number might change if transactions  are
+         reordered  within  the file, files are parsed/included in a different
          order, etc.)
 
-       o The  amount  is  separated into "commodity" (the symbol) and "amount"
+       o The amount is separated into "commodity" (the  symbol)  and  "amount"
          (numeric quantity) fields.
 
        o The numeric amount is repeated in either the "credit" or "debit" col-
-         umn,  for convenience.  (Those names are not accurate in the account-
-         ing sense; it just puts negative amounts under  credit  and  zero  or
+         umn, for convenience.  (Those names are not accurate in the  account-
+         ing  sense;  it  just  puts negative amounts under credit and zero or
          greater amounts under debit.)
 
    print-unique
@@ -1852,7 +1860,7 @@
               show running total from report start date (default)
 
        -H --historical
-              show  historical running total/balance (includes postings before
+              show historical running total/balance (includes postings  before
               report start date)
 
        -A --average
@@ -1863,18 +1871,18 @@
               show postings' siblings instead
 
        -w N --width=N
-              set  output  width  (default:  terminal width or COLUMNS.  -wN,M
+              set output width (default: terminal  width  or  COLUMNS.   -wN,M
               sets description width as well)
 
        -O FMT --output-format=FMT
               select the output format.  Supported formats: txt, csv.
 
        -o FILE --output-file=FILE
-              write output to FILE.  A file  extension  matching  one  of  the
+              write  output  to  FILE.   A  file extension matching one of the
               above formats selects that format.
 
        The register command displays postings, one per line, and their running
-       total.  This is typically used with  a  query  selecting  a  particular
+       total.   This  is  typically  used  with a query selecting a particular
        account, to see that account's activity:
 
               $ hledger register checking
@@ -1883,8 +1891,8 @@
               2008/06/02 save                 assets:bank:checking           $-1            $1
               2008/12/31 pay off              assets:bank:checking           $-1             0
 
-       The  --historical/-H  flag  adds the balance from any undisplayed prior
-       postings to the running total.  This is useful when  you  want  to  see
+       The --historical/-H flag adds the balance from  any  undisplayed  prior
+       postings  to  the  running  total.  This is useful when you want to see
        only recent activity, with a historically accurate running balance:
 
               $ hledger register checking -b 2008/6 --historical
@@ -1894,23 +1902,23 @@
 
        The --depth option limits the amount of sub-account detail displayed.
 
-       The  --average/-A flag shows the running average posting amount instead
+       The --average/-A flag shows the running average posting amount  instead
        of the running total (so, the final number displayed is the average for
-       the  whole  report period).  This flag implies --empty (see below).  It
-       is affected by --historical.  It  works  best  when  showing  just  one
+       the whole report period).  This flag implies --empty (see  below).   It
+       is  affected  by  --historical.   It  works  best when showing just one
        account and one commodity.
 
-       The  --related/-r  flag shows the other postings in the transactions of
+       The --related/-r flag shows the other postings in the  transactions  of
        the postings which would normally be shown.
 
-       With a reporting interval, register shows  summary  postings,  one  per
+       With  a  reporting  interval,  register shows summary postings, one per
        interval, aggregating the postings to each account:
 
               $ hledger register --monthly income
               2008/01                 income:salary                          $-1           $-1
               2008/06                 income:gifts                           $-1           $-2
 
-       Periods  with no activity, and summary postings with a zero amount, are
+       Periods with no activity, and summary postings with a zero amount,  are
        not shown by default; use the --empty/-E flag to see them:
 
               $ hledger register --monthly income -E
@@ -1927,7 +1935,7 @@
               2008/11                                                          0           $-2
               2008/12                                                          0           $-2
 
-       Often, you'll want to see just one  line  per  interval.   The  --depth
+       Often,  you'll  want  to  see  just one line per interval.  The --depth
        option helps with this, causing subaccounts to be aggregated:
 
               $ hledger register --monthly assets --depth 1h
@@ -1935,18 +1943,18 @@
               2008/06                 assets                                 $-1             0
               2008/12                 assets                                 $-1           $-1
 
-       Note  when using report intervals, if you specify start/end dates these
-       will be adjusted outward if necessary to  contain  a  whole  number  of
-       intervals.   This  ensures  that  the first and last intervals are full
+       Note when using report intervals, if you specify start/end dates  these
+       will  be  adjusted  outward  if  necessary to contain a whole number of
+       intervals.  This ensures that the first and  last  intervals  are  full
        length and comparable to the others in the report.
 
    Custom register output
-       register uses the full terminal width by default,  except  on  windows.
-       You  can override this by setting the COLUMNS environment variable (not
+       register  uses  the  full terminal width by default, except on windows.
+       You can override this by setting the COLUMNS environment variable  (not
        a bash shell variable) or by using the --width/-w option.
 
-       The description and account columns normally share  the  space  equally
-       (about  half  of  (width  - 40) each).  You can adjust this by adding a
+       The  description  and  account columns normally share the space equally
+       (about half of (width - 40) each).  You can adjust  this  by  adding  a
        description  width  as  part  of  -width's  argument,  comma-separated:
        --width W,D .  Here's a diagram:
 
@@ -1963,17 +1971,21 @@
               $ hledger reg -w 100,40           # set overall width 100, description width 40
               $ hledger reg -w $COLUMNS,40      # use terminal width, and set description width
 
-       This  command also supports output destination and output format selec-
+       This command also supports output destination and output format  selec-
        tion.
 
    register-match
        Print the one posting whose transaction description is closest to DESC,
-       in  the  style  of  the register command.  Helps ledger-autosync detect
+       in the style of the register  command.   Helps  ledger-autosync  detect
        already-seen transactions when importing.
 
    rewrite
        Print all transactions, adding custom postings to the matched ones.
 
+   roi
+       Shows  time-weighted  (TWR)  and money-weighted (IRR) rate of return on
+       your investments.  See roi --help for more.
+
    stats
        Show some journal statistics.
 
@@ -2009,37 +2021,45 @@
    test
        Run built-in unit tests.
 
-              $ hledger test
-              Cases: 74  Tried: 74  Errors: 0  Failures: 0
+       Prints  test  names  and their results on stdout.  If any test fails or
+       gives an error, the exit code will be non-zero.
 
-       This  command  runs  hledger's built-in unit tests and displays a quick
-       report.  With a regular expression argument, it selects only tests with
-       matching names.  It's mainly used in development, but it's also nice to
-       be able to check your hledger executable for smoke at any time.
+       Test names include a group prefix.  If a (exact, case sensitive)  group
+       prefix,  or  a  full  test name is provided as the first argument, only
+       that group or test is run.
 
+       If a numeric second argument is provided, it will  set  the  randomness
+       seed,  for  repeatable  results  from tests using randomness (currently
+       none of them).
+
+       This is mainly used by developers, but it's nice to  be  able  to  san-
+       ity-check your installed hledger executable at any time.  All tests are
+       expected to pass - if you ever see otherwise, something has gone wrong,
+       please report a bug!
+
 ADD-ON COMMANDS
-       hledger also searches for external add-on commands,  and  will  include
+       hledger  also  searches  for external add-on commands, and will include
        these in the commands list.  These are programs or scripts in your PATH
-       whose name starts with hledger- and ends with a recognised file  exten-
+       whose  name starts with hledger- and ends with a recognised file exten-
        sion (currently: no extension, bat,com,exe, hs,lhs,pl,py,rb,rkt,sh).
 
-       Add-ons  can  be  invoked like any hledger command, but there are a few
+       Add-ons can be invoked like any hledger command, but there  are  a  few
        things to be aware of.  Eg if the hledger-web add-on is installed,
 
        o hledger -h web  shows  hledger's  help,  while  hledger web -h  shows
          hledger-web's help.
 
-       o Flags  specific  to  the add-on must have a preceding -- to hide them
-         from hledger.  So hledger web --serve --port 9000 will  be  rejected;
+       o Flags specific to the add-on must have a preceding --  to  hide  them
+         from  hledger.   So hledger web --serve --port 9000 will be rejected;
          you must use hledger web -- --serve --port 9000.
 
-       o You    can    always    run    add-ons    directly    if   preferred:
+       o You   can    always    run    add-ons    directly    if    preferred:
          hledger-web --serve --port 9000.
 
-       Add-ons are a relatively easy way to add local features  or  experiment
-       with  new  ideas.   They  can  be  written in any language, but haskell
-       scripts have a big advantage:  they  can  use  the  same  hledger  (and
-       haskell)  library functions that built-in commands do, for command-line
+       Add-ons  are  a relatively easy way to add local features or experiment
+       with new ideas.  They can be  written  in  any  language,  but  haskell
+       scripts  have  a  big  advantage:  they  can  use the same hledger (and
+       haskell) library functions that built-in commands do, for  command-line
        options, journal parsing, reporting, etc.
 
        Here are some hledger add-ons available:
@@ -2057,7 +2077,7 @@
        hledger-web provides a simple web interface.
 
    Third party add-ons
-       These are maintained separately, and usually updated  shortly  after  a
+       These  are  maintained  separately, and usually updated shortly after a
        hledger release.
 
    diff
@@ -2065,7 +2085,7 @@
        journal file and another.
 
    iadd
-       hledger-iadd is a curses-style, more interactive  replacement  for  the
+       hledger-iadd  is  a  curses-style, more interactive replacement for the
        add command.
 
    interest
@@ -2073,19 +2093,19 @@
        ing to various schemes.
 
    irr
-       hledger-irr calculates the internal rate of  return  of  an  investment
+       hledger-irr  calculates  the  internal  rate of return of an investment
        account.
 
    Experimental add-ons
-       These  are  available  in source form in the hledger repo's bin/ direc-
+       These are available in source form in the hledger  repo's  bin/  direc-
        tory; installing them is pretty easy.  They may be less mature and doc-
-       umented  than  built-in commands.  Reading and tweaking these is a good
+       umented than built-in commands.  Reading and tweaking these is  a  good
        way to start making your own!
 
    autosync
        hledger-autosync is a symbolic link for easily running ledger-autosync,
-       if  installed.   ledger-autosync  does  deduplicating conversion of OFX
-       data and some CSV formats, and can also download the data if your  bank
+       if installed.  ledger-autosync does  deduplicating  conversion  of  OFX
+       data  and some CSV formats, and can also download the data if your bank
        offers OFX Direct Connect.
 
    chart
@@ -2095,21 +2115,21 @@
        hledger-check.hs checks more powerful account balance assertions.
 
 ENVIRONMENT
-       COLUMNS  The  screen  width used by the register command.  Default: the
+       COLUMNS The screen width used by the register  command.   Default:  the
        full terminal width.
 
        LEDGER_FILE The journal file path when not specified with -f.  Default:
-       ~/.hledger.journal  (on  windows,  perhaps C:/Users/USER/.hledger.jour-
+       ~/.hledger.journal (on  windows,  perhaps  C:/Users/USER/.hledger.jour-
        nal).
 
 FILES
-       Reads data from one or more files in hledger journal, timeclock,  time-
-       dot,   or   CSV   format   specified   with  -f,  or  $LEDGER_FILE,  or
-       $HOME/.hledger.journal          (on          windows,           perhaps
+       Reads  data from one or more files in hledger journal, timeclock, time-
+       dot,  or  CSV  format  specified   with   -f,   or   $LEDGER_FILE,   or
+       $HOME/.hledger.journal           (on          windows,          perhaps
        C:/Users/USER/.hledger.journal).
 
 BUGS
-       The  need  to  precede  addon command options with -- when invoked from
+       The need to precede addon command options with  --  when  invoked  from
        hledger is awkward.
 
        When input data contains non-ascii characters, a suitable system locale
@@ -2122,33 +2142,33 @@
        In a Cygwin/MSYS/Mintty window, the tab key is not supported in hledger
        add.
 
-       Not all of Ledger's journal file syntax is supported.  See file  format
+       Not  all of Ledger's journal file syntax is supported.  See file format
        differences.
 
-       On  large  data  files,  hledger  is  slower  and uses more memory than
+       On large data files, hledger  is  slower  and  uses  more  memory  than
        Ledger.
 
 TROUBLESHOOTING
-       Here are some issues you might encounter  when  you  run  hledger  (and
-       remember  you can also seek help from the IRC channel, mail list or bug
+       Here  are  some  issues  you  might encounter when you run hledger (and
+       remember you can also seek help from the IRC channel, mail list or  bug
        tracker):
 
        Successfully installed, but "No command `hledger' found"
        stack and cabal install binaries into a special directory, which should
-       be  added  to your PATH environment variable.  Eg on unix-like systems,
+       be added to your PATH environment variable.  Eg on  unix-like  systems,
        that is ~/.local/bin and ~/.cabal/bin respectively.
 
        I set a custom LEDGER_FILE, but hledger is still using the default file
-       LEDGER_FILE  should  be  a  real environment variable, not just a shell
-       variable.  The command env | grep LEDGER_FILE should show it.  You  may
+       LEDGER_FILE should be a real environment variable,  not  just  a  shell
+       variable.   The command env | grep LEDGER_FILE should show it.  You may
        need to use export.  Here's an explanation.
 
-       "Illegal  byte  sequence"  or  "Invalid or incomplete multibyte or wide
+       "Illegal byte sequence" or "Invalid or  incomplete  multibyte  or  wide
        character" errors
        In order to handle non-ascii letters and symbols (like ), hledger needs
        an appropriate locale.  This is usually configured system-wide; you can
        also configure it temporarily.  The locale may need to be one that sup-
-       ports  UTF-8,  if you built hledger with GHC < 7.2 (or possibly always,
+       ports UTF-8, if you built hledger with GHC < 7.2 (or  possibly  always,
        I'm not sure yet).
 
        Here's  an  example  of  setting  the  locale  temporarily,  on  ubuntu
@@ -2167,7 +2187,7 @@
               $ echo "export LANG=en_US.UTF-8" >>~/.bash_profile
               $ bash --login
 
-       If  we  preferred  to  use eg fr_FR.utf8, we might have to install that
+       If we preferred to use eg fr_FR.utf8, we might  have  to  install  that
        first:
 
               $ apt-get install language-pack-fr
@@ -2188,7 +2208,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)
 
 
@@ -2202,7 +2222,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)
 
@@ -2210,4 +2230,4 @@
 
 
 
-hledger 1.9.99                     June 2018                        hledger(1)
+hledger 1.10.99                 September 2018                      hledger(1)
diff --git a/test/test.hs b/test/test.hs
--- a/test/test.hs
+++ b/test/test.hs
@@ -1,13 +1,8 @@
-import Hledger.Cli (tests_Hledger_Cli)
-import System.Environment (getArgs)
-import Test.Framework.Providers.HUnit (hUnitTestToTests)
-import Test.Framework.Runners.Console (defaultMainWithArgs)
-
-main :: IO ()
-main = do
-  args <- getArgs
-  let args' = "--hide-successes" : args
-  defaultMainWithArgs (hUnitTestToTests tests_Hledger_Cli) args'
-
+{-
+Run hledger's (and hledger-lib's) unit tests as a cabal test suite,
+by running the test command with no options.
+-}
 
+import Hledger.Cli
 
+main = testcmd defcliopts (error "journal-less command tried to use the journal")
