Resolve double auction orders Given a vector of seller orders (asks) of a certain product (each order having a price) and buyer orders (bids) of the same product, I'm creating a function that resolves the auction by matching the best sellers (lowest asked price) with the best buyers (higher offered price) and then clears the market by selecting a price and 'performing' the transactions between all suitable traders.

I'm experienced as programmer but I'm new to Clojure (or any Lisp), so this question is about the "Clojure way" of doing things so that the resulting code is readable, maintainable and efficient. 

(ns trade-routes.core
  (:gen-class))


(defn as-trade-result 
  [ask bid]
  (let [bid-price (:price bid) ask-price (:price ask)]
    {:traded (&lt;= ask-price bid-price) :bid bid :ask ask}
    )
)

(defn trade-price-tagger
  [price]
    (fn [trade] (merge trade {:price price}))
  )

(defn bid-price
  [trade]
  (-&gt; trade :bid :price))

(defn average
  [a b]
  (* 0.5 (+ a b)))

(defn resolve-auction
  "Returns a list of trades and unresolved seller asks orders and buyer bids orders.
  The highest asks are matched with the lowest bids until all bids are greater than all asks"
  [asks bids]
  (let [best-asks (sort-by :price asks) 
        best-bids (reverse (sort-by :price bids))
        succesful-trades (first (partition-by 
            :traded 
            (map as-trade-result
                 best-asks 
                 best-bids)))
        breakeven-successful-trade (last succesful-trades)
        breakeven-price (average 
                          (bid-price breakeven-successful-trade) 
                          (bid-price breakeven-successful-trade))]
    (map (trade-price-tagger breakeven-price) succesful-trades)))

(defn random-order
    [min max]
    {:price (+ min (rand (- max min)))}
  )

(defn gen-random-orders
    "Create 'total' random orders with price between min and max"
    [total min max]
   (take total (repeatedly #(random-order min max)))
  )

(def test-asks (gen-random-orders 1000 20 100))
(def test-bids (gen-random-orders 1000 0 25))

(defn -main
  "Just tests with test-asks and test-bids."
  [&amp; args]
  (let [succesful-trades (resolve-auction test-asks test-bids)]
   (println (str "There were " (count succesful-trades) " trades"))))
Formatting

It's common to see let-bindings vertically aligned, one per line. You've done that further down in resolve-auction, but even with just two name-value pairs it can be easier to see the logical parts vertically. The closing brackets (any kind) are also usually on the last line of the form, as opposed to indented back out. So

(defn as-trade-result 
  [ask bid]
  (let [bid-price (:price bid) ask-price (:price ask)]
    {:traded (&lt;= ask-price bid-price) :bid bid :ask ask}
    )
)


would more idiomatically be formatted as

(defn as-trade-result
  [ask bid]
  (let [bid-price (:price bid)
        ask-price (:price ask)]
    {:traded (&lt;= ask-price bid-price)
     :ask ask
     :bid bid}))


Semantic indentation

Also, the indentation here with (first (partition-by ending the line:

(let [best-asks (sort-by :price asks) 
      best-bids (reverse (sort-by :price bids))
      succesful-trades (first (partition-by 
          :traded 
          (map as-trade-result
               best-asks 
               best-bids)))


would more commonly be written in a way that reads left-to-right, top-to-bottom, in terms of expressions. Here are some examples:

(let [best-asks (sort-by :price asks)
      best-bids (sort-by (comp - :price) bids) ; negated :price gives you (reverse) in a single pass
      successful-trades
      (first
        (partition-by :traded (map as-trade-result best-asks best-bids)))]

      ; or

      successful-trades
      (-&gt;&gt; (map as-trade-result best-asks best-bids)
           (partition-by :traded)
           first)


The point here is that the indentation is not just a continuation, but actually shows the code structure. Something in the (bottom) right is expected to flow towards the (top) left.

When you get used to this it makes reading code much faster because it's easy to see what is dependent on what, structure-wise.

Side note: since you only want the first group the partition-by is overkill. Consider take-while:

      successful-trades
      (-&gt;&gt; (map as-trade-result best-asks best-bids)
           (take-while :traded))




Expose more of the data

There is a balance here between encapsulating complex logic and making things clear. Someone familiar with Clojure knows instantly what assoc, merge, and so on mean. It's less clear exactly what a trade-price-tagger does until one looks it up. For relatively simple cases like that, using an inline function is idiomatic and arguably more clear. Compare:

(defn trade-price-tagger
  [price]
    (fn [trade] (merge trade {:price price}))
  )
...
(map (trade-price-tagger breakeven-price) succesful-trades)


with

(map #(assoc % :price breakeven-price) succesful-trades)


Similarly, accessors like

(defn bid-price
  [trade]
  (-&gt; trade :bid :price))

(bid-price breakeven-successful-trade)


can be useful for deep objects or large programs, but in something short like this (get-in) could be fine:

(get-in breakeven-successful-trade [:bid :price])




In general I think this is readable and reasonably structured. Nice work as someone new to Clojure/Lisp!

My only other suggestion would be potentially to split up resolve-auction. The first half could be a function (defn get-successful-trades [asks bids]), and resolve-auction could just do the tagging of the breakeven point.