diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2011 Peter Simons <simons@cryp.to>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Peter Simons nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,198 @@
+module Main ( main ) where
+
+import Hledger
+
+import Control.Exception ( bracket )
+import Control.Monad
+import Distribution.Text ( display )
+import System.Console.GetOpt
+import System.Environment
+import System.Exit
+import System.IO
+import Data.Time.Calendar
+import Text.Printf
+import Data.List
+import Data.Ord
+import Statistics.Math.RootFinding
+
+
+import Paths_hledger_irr ( version )
+
+data Options = Options
+  { optShowVersion  :: Bool
+  , optShowHelp     :: Bool
+  , optCashFlow     :: Bool
+  , optInput        :: FilePath
+  , optInvAcc       :: String
+  , optInterestAcc  :: String
+  , optBegin        :: Maybe String
+  , optEnd          :: Maybe String
+  , optInterval     :: Maybe Interval
+  }
+
+defaultOptions :: Options
+defaultOptions = Options
+  { optShowVersion  = False
+  , optShowHelp     = False
+  , optCashFlow     = False
+  , optInput        = "-"
+  , optInvAcc       = ""
+  , optInterestAcc  = ""
+  , optBegin        = Nothing
+  , optEnd          = Nothing
+  , optInterval     = Nothing
+  }
+
+options :: [OptDescr (Options -> Options)]
+options =
+ [ Option "h" ["help"]
+              (NoArg (\o -> o { optShowHelp = True }))
+              "print this message and exit"
+ , Option "V" ["version"]
+              (NoArg (\o -> o { optShowVersion = True }))
+              "show version number and exit"
+ , Option "c" ["cashflow"]
+              (NoArg (\o -> o { optCashFlow = True }))
+              "also show all revant transactions"
+ , Option "f" ["file"]
+              (ReqArg (\f o -> o { optInput = f }) "FILE")
+              "input ledger file (pass '-' for stdin)"
+ , Option "i" ["investment-account"]
+              (ReqArg (\a o -> o { optInvAcc = a }) "ACCOUNT")
+              "investment account"
+ , Option "t" ["interest-account"]
+              (ReqArg (\a o -> o { optInterestAcc = a }) "ACCOUNT")
+              "interest/gain/fees/losses account"
+ , Option "b" ["begin"]
+              (ReqArg (\d o -> o { optBegin = Just d }) "DATE")
+              "calculate interest from this date"
+ , Option "e" ["end"]
+              (ReqArg (\d o -> o { optEnd = Just d }) "DATE")
+              "calculate interest until this date"
+ , Option "D" ["daily"]
+              (NoArg (\o -> o { optInterval = Just (Days 1) }))
+              "calculate intereste for each day"
+ , Option "W" ["weekly"]
+              (NoArg (\o -> o { optInterval = Just (Weeks 1) }))
+              "calculate intereste for each week"
+ , Option "M" ["monthly"]
+              (NoArg (\o -> o { optInterval = Just (Months 1) }))
+              "calculate intereste for each month"
+ , Option "Y" ["yearly"]
+              (NoArg (\o -> o { optInterval = Just (Years 1) }))
+              "calculate intereste for each year"
+ ]
+
+usageMessage :: String
+usageMessage = usageInfo header options
+  where header = "Usage: hledger-irr [OPTION...]"
+
+commandLineError :: String -> IO a
+commandLineError err = do hPutStrLn stderr (err ++ usageMessage)
+                          exitFailure
+
+parseOpts :: [String] -> IO (Options, [String])
+parseOpts argv =
+   case getOpt Permute options argv of
+      (o,n,[]  ) -> return (foldl (flip id) defaultOptions o, n)
+      (_,_,errs) -> commandLineError (concat errs)
+
+main :: IO ()
+main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
+  (opts, args) <- getArgs >>= parseOpts
+  when (optShowVersion opts) (putStrLn (display version) >> exitSuccess)
+  when (optShowHelp opts) (putStr usageMessage >> exitSuccess)
+  when (null (optInvAcc opts)) (commandLineError "required --investment-account option is missing\n")
+  when (null (optInterestAcc opts)) (commandLineError "required --interest-account option is missing\n")
+  when (length args > 0) (commandLineError "no command line arguments allowed")
+  jnl' <- readJournalFile Nothing Nothing (optInput opts) >>= either fail return
+
+  let ts = jtxns $ filterJournalTransactions (Acct (optInvAcc opts)) jnl'
+  when (null ts) $ do
+    putStrLn "No relevant transactions found. Did you mis-spell your accounts?"
+    exitFailure
+
+  thisDay <- getCurrentDay
+  let firstDay = minimum $ map transactionEffectiveDate ts
+  let lastDay = maximum $ map transactionEffectiveDate ts
+  let existingSpan = DateSpan (Just firstDay) (Just lastDay)
+
+  let begin = maybe firstDay (fixSmartDateStr' thisDay) (optBegin opts)
+  let end =   maybe thisDay  (fixSmartDateStr' thisDay) (optEnd opts)
+  let wholeSpan = DateSpan (Just begin) (Just end)
+
+  let spans = case optInterval opts of
+        Nothing -> [wholeSpan]
+        Just interval ->
+            splitSpan interval $
+            spanIntersect existingSpan wholeSpan
+
+  forM_ spans $ \(DateSpan (Just ibegin) (Just iend)) -> do
+      let preQuery = And [ Acct (optInvAcc opts),
+                           EDate (openClosedSpan Nothing (Just ibegin))]
+          pre_amount = negate $ unMix $ accountAmount preQuery ts
+      let prefix = (ibegin, pre_amount)
+
+      let eQuery = And [Acct (optInvAcc opts), EDate (openClosedSpan Nothing (Just iend))]
+      let final = unMix $ accountAmount eQuery ts
+      let postfix = (iend, final)
+
+      let cfQuery = And [ Not (Or [Acct (optInvAcc opts), Acct (optInterestAcc opts)]), 
+                          EDate (openClosedSpan (Just ibegin) (Just iend)) ] 
+      let cf = calculateCashFlow cfQuery ts
+
+      let totalCF = sortBy (comparing fst) $ filter ((/=0) . aquantity . snd) $ prefix : cf ++ [postfix]
+
+      when (optCashFlow opts) $ do
+          mapM_ (putStrLn . showCashFlowEntry) totalCF
+
+      -- 0% is always a solution, so require at least something here
+      putStr $ printf "%s - %s: " (showDate ibegin) (showDate iend)
+      case ridders 0.00001 (0.000001,1000) (aquantity . interestSum iend totalCF) of
+        Root rate -> putStrLn (printf "%0.2f%%" ((rate-1)*100))
+        _ -> putStrLn "Error: Failed to find solution."
+
+openClosedSpan :: Maybe Day -> Maybe Day -> DateSpan
+openClosedSpan md1 md2 = DateSpan (fmap (addDays 1) md1) (fmap (addDays 1) md2)
+
+
+-- Bad hack – what to do?
+unMix :: MixedAmount -> Amount
+unMix = sum . amounts
+
+
+showCashFlowEntry :: (Day, Amount) -> String
+showCashFlowEntry (d, a) = showDate d ++ ": " ++ showAmount a
+
+type CashFlow = [(Day, Amount)]
+
+
+-- | Divide an amount's quantity by a constant.
+multiplyAmount :: Amount -> Double -> Amount
+multiplyAmount a@Amount{aquantity=q} d = a{aquantity=q*d}
+
+
+interestSum :: Day -> CashFlow -> Double -> Amount
+interestSum referenceDay cf rate = sum $ map go cf
+    where go (t,m) = multiplyAmount m (rate ** (fromIntegral (referenceDay `diffDays` t) / 365))
+
+
+calculateCashFlow :: Query -> [Transaction] -> CashFlow
+calculateCashFlow query = map go
+    where
+    go t = (transactionEffectiveDate t, amt)
+        where
+        amt = sum $
+              map (unMix . pamount) $ filter (matchesPosting query) $
+              realPostings t
+
+accountAmount :: Query -> [Transaction] -> MixedAmount
+accountAmount query = sumPostings . filter (matchesPosting query) . concatMap realPostings 
+
+-- | Convert a smart date string to a day using
+-- the provided reference date, or raise an error.
+fixSmartDateStr' :: Day -> String -> Day
+fixSmartDateStr' d s = either
+                       (\e->error' $ printf "could not parse date %s %s" (show s) (show e))
+                       id
+                       $ fixSmartDateStrEither' d s
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/hledger-irr.cabal b/hledger-irr.cabal
new file mode 100644
--- /dev/null
+++ b/hledger-irr.cabal
@@ -0,0 +1,113 @@
+Name:                   hledger-irr
+Version:                0.1
+Synopsis:               computes the internal rate of return of an investment
+License:                BSD3
+License-file:           LICENSE
+Author:                 Joachim Breitner <mail@joachim-breitner.de>
+Maintainer:             Joachim Breitner <mail@joachim-breitner.de>
+Category:               Finance
+Build-type:             Simple
+Cabal-version:          >= 1.6
+Tested-with:            GHC >= 7.4.1 && <= 7.4.1
+Description:
+ hledger-irr is a small command-line utility based on Simon
+ Michael's hleder library. Its purpose is to compute the internal rate of
+ return, also known as the effective interest rate, of a given investment.
+ After specifying what account holds the investment, and what account stores
+ the gains (or losses, or fees, or cost), it calculates the hypothetical
+ annualy rate of fixed rate investment that would have provided the exact same
+ cash flow.
+ .
+ As an example, consider the following irregular investment recorded in a file
+ called @speculation.ledger@. The account “Speculation” holds the investment which
+ could be, for example, a stock. Regularly, we make sure that the value of the
+ account matches the value of the stock, by moving money from or to the account
+ “Rate Gain”. It does not really matter when we adjust the price, as long as it
+ is correct at the end of our reporting period.
+ .
+ > 2011-01-01 Some wild speculation – I wonder if it pays off
+ >   Speculation   €100.00
+ >   Cash
+ > 
+ > 2011-02-01 More speculation (and adjustment of value)
+ >   Cash         -€10.00
+ >   Rate Gain     -€1.00 
+ >   Speculation
+ > 
+ > 2011-03-01 Lets pull out some money (and adjustment of value)
+ >   Cash          €30.00
+ >   Rate Gain     -€3.00 
+ >   Speculation
+ > 
+ > 2011-04-01 More speculation (and it lost some money!)
+ >   Cash         -€50.00
+ >   Rate Gain     € 5.00
+ >   Speculation
+ > 
+ > 2011-05-01 Getting some money out (and adjustment of value)
+ >   Speculation  -€44.00
+ >   Rate Gain    -€ 3.00
+ >   Cash
+ > 
+ > 2011-06-01 Emptying the account (after adjusting the value)
+ >   Speculation   -€85.00
+ >   Cash           €90.00
+ >   Rate Gain     -€ 5.00
+ .
+ We can now calculate the rate of return for the whole time or just for parts
+ of it (and be freaked out by the volatility of the investment):
+ .
+ > $ hledger-irr -f speculation.ledger -t "Rate Gain" -i Speculation -c
+ > 2011/01/01: €-100.00
+ > 2011/02/01: €-10.00
+ > 2011/03/01: €30.00
+ > 2011/04/01: €-50.00
+ > 2011/05/01: €47.00
+ > 2011/06/01: €90.00
+ > 2011/01/01 - 2012/12/07: 17.72%
+ > $ hledger-irr -f speculation.ledger -t "Rate Gain" -i Speculation -e 2011-03-01
+ > 2011/01/01 - 2011/03/01: 26.11%
+ > $ hledger-irr -f speculation.ledger -t "Rate Gain" -i Speculation -b 2011-03-01
+ > 2011/03/01 - 2012/12/07: 12.28%
+ > $ hledger-irr -f speculation.ledger -t "Rate Gain" -i Speculation --monthly
+ > 2011/01/01 - 2011/02/01: 12.43%
+ > 2011/02/01 - 2011/03/01: 41.57%
+ > 2011/03/01 - 2011/04/01: -51.45%
+ > 2011/04/01 - 2011/05/01: 32.27%
+ > 2011/05/01 - 2011/06/01: 96.01%
+ .
+ Running the utility with @--help@ gives a brief overview over the
+ available options:
+ .
+ > $ hledger-irr --help
+ > Usage: hledger-irr [OPTION...]
+ >   -h          --help                        print this message and exit
+ >   -V          --version                     show version number and exit
+ >   -c          --cashflow                    also show all revant transactions
+ >   -f FILE     --file=FILE                   input ledger file (pass '-' for stdin)
+ >   -i ACCOUNT  --investment-account=ACCOUNT  investment account
+ >   -t ACCOUNT  --interest-account=ACCOUNT    interest/gain/fees/losses account
+ >   -b DATE     --begin=DATE                  calculate interest from this date
+ >   -e DATE     --end=DATE                    calculate interest until this date
+ >   -D          --daily                       calculate intereste for each day
+ >   -W          --weekly                      calculate intereste for each week
+ >   -M          --monthly                     calculate intereste for each month
+ >   -Y          --yearly                      calculate intereste for each year
+ .
+ Known bugs and issues:
+ .
+ * Currenlty, hledger-irr does not cope well with multiple commodities (e.g.
+   Euro and Dollar, or shares).
+ .
+ * Also, interest or fees that do not pass through the account selected by
+   @--investment-account@ are not taken into consideration.
+
+Executable hledger-irr
+  Main-is:              Main.hs
+  Build-depends:        base >= 3 && < 5, hledger-lib >= 0.19.3, time, Cabal, statistics >= 0.10
+  Ghc-Options:          -Wall
+
+source-repository head
+    type:     darcs
+    location: http://darcs.nomeata.de/hledger-irr
+
