first draft of the stock exchange

This commit is contained in:
didier amyot committed 2018-06-01 19:04:52 -04:00
1 parent b1ba21f391
commit c099924a89
7 files changed
+296 -24

No files matched your search

+77 -2
View File
@@ -1,5 +1,80 @@
(ns book.core)
(ns book.core
(:require [book.match :refer [sell?
create-buy-book
create-sell-book
match-order-in-book]]
[book.util :refer :all]
[book.order] ;; for spec side effect
[clojure.edn :as edn]
[clojure.core.async :refer [chan go >!! <!!]]
[clojure.spec.alpha :as s])
(:gen-class))
(def incoming-order-channel (chan))
(def trades-channel (chan))
(def new-book-order-channel (chan))
(defn print-chan [prefix c]
(loop [shit (<!! c)]
(println prefix shit)
(recur (<!! c))))
(def master-book {:sell (create-sell-book)
:buy (create-buy-book)})
;
;(defn process-buy-order [order]
; (let [[x y x] (match-order-in-book @buy-book order)]))
;;; repl things.
(defn read-order []
(try
(print "$ ")
(let [order (edn/read-string (read-line))
valid? (s/valid? :book.order/order order)]
(if valid? order nil))
(catch Exception e nil)))
(def order-ids (atom -1))
(defn add-id-to-order [order]
(assoc order :book.order/id (swap! order-ids inc)))
(defn process-orders [master-book orders-channel trades-channel new-book-order-channel]
(loop [order (<!! orders-channel)
{sell-book :sell buy-book :buy} master-book]
(if (sell? order)
(do
(let [[trades new-buy-book leftover-order] (match-order-in-book buy-book order)
new-sell-book (if leftover-order (conj sell-book) leftover-order)]
(when (seq trades) (>!! trades-channel trades))
(when leftover-order (>!! new-book-order-channel leftover-order))
(recur (<!! orders-channel) {:sell new-sell-book :buy new-buy-book})))
(do
(let [[trades new-sell-book leftover-order] (match-order-in-book sell-book order)
new-buy-book (if leftover-order (conj buy-book) leftover-order)]
(when (seq trades) (>!! trades-channel trades))
(when leftover-order (>!! new-book-order-channel leftover-order))
(recur (<!! orders-channel) {:sell new-sell-book :buy new-buy-book}))))))
(defn -main [& args]
(println "hello workd"))
(println "enter orders in edn format.")
(go (print-chan "trade > " trades-channel))
(go (print-chan "order > " new-book-order-channel))
(go (process-orders master-book incoming-order-channel trades-channel new-book-order-channel))
(loop [order (read-order)]
(if (some? order)
(do
(let [order-with-id (add-id-to-order order)]
(>!! incoming-order-channel order-with-id)
(println "\n\norder accepted with id: " (:book.order/id order-with-id))))
(println "invalid order"))
(recur (read-order))))
+6 -14
View File
@@ -1,17 +1,9 @@
(ns book.match
(:import [book.PersistentSortedList])
(:require [book.order]
(:require [book.util :refer [sorted-list-by]]
[clojure.spec.alpha :as s]
[clojure.edn :as edn])
(:gen-class))
[clojure.edn :as edn]))
(defn sorted-list [& keys]
(book.PersistentSortedList/create (seq keys)))
(defn sorted-list-by [comparator & keys]
(book.PersistentSortedList/create comparator (seq keys)))
;; Let say a book is two collections. The first called
;; sell-book contains all the sell orders. The second
@@ -95,9 +87,9 @@
(when (pos? leftover-quantity)
(assoc order :quantity leftover-quantity))))
(defn match-order-in-book [sell-book order]
(let [trades (create-trades order sell-book)
new-book (compute-new-book-after-trades sell-book trades)
(defn match-order-in-book [book order]
(let [trades (create-trades order book)
new-book (compute-new-book-after-trades book trades)
new-buy-order (leftover-order order trades)]
[trades new-book new-buy-order]))
@@ -112,7 +104,7 @@
;
;(defn -main
; [& args]
; (let [order (-> args first edn/read-string)]
; (let [order (-> a+rgs first edn/read-string)]
; (if (not (s/valid? :book.order/order order))
; (println "invalid order :( ")
; (println (place-order book order)))))
+9
View File
@@ -0,0 +1,9 @@
(ns book.util
(:import [book.PersistentSortedList]))
(defn sorted-list [& keys]
(book.PersistentSortedList/create (seq keys)))
(defn sorted-list-by [comparator & keys]
(book.PersistentSortedList/create comparator (seq keys)))
+187 -5
View File
@@ -3,10 +3,18 @@ package book;
import clojure.lang.*;
import java.util.*;
public class PersistentSortedList extends ASeq implements IPersistentList, IReduce, List, Counted{
//IPersistentVector, Iterable,
// List,
// RandomAccess, Comparable,
// Serializable, IHashEq
public class PersistentSortedList extends Obj implements Iterable, RandomAccess, Comparable,
IHashEq, IPersistentList, IReduce, ISeq,
List, Counted{
final private PersistentTreeMap impl;
final private int _count;
static public final PersistentSortedList EMPTY = new PersistentSortedList(null, PersistentTreeMap.EMPTY, 0);
private int _hasheq = 0;
public static PersistentSortedList create(ISeq items){
PersistentSortedList ret = EMPTY;
@@ -42,6 +50,24 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
return new PersistentSortedList(meta(), impl.assoc(o, newList), _count + 1);
}
@Override
public IPersistentCollection empty() {
return PersistentSortedList.EMPTY;
}
@Override
public boolean equiv(Object obj) {
if(!(obj instanceof Sequential || obj instanceof List))
return false;
ISeq ms = RT.seq(obj);
for(ISeq s = seq(); s != null; s = s.next(), ms = ms.next()){
if(ms == null || !Util.equiv(s.first(), ms.first())){
return false;
}
}
return ms == null;
}
@Override
public Object peek() {
if(_count == 0){
@@ -70,7 +96,7 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
@Override
public Object reduce(IFn f) {
Object ret = first();
for(ISeq s = next(); s != null; s = s.next()) {
for(ISeq s = (ISeq) next(); s != null; s = s.next()) {
ret = f.invoke(ret, s.first());
if (RT.isReduced(ret)) return ((IDeref)ret).deref();
}
@@ -80,7 +106,7 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
@Override
public Object reduce(IFn f, Object start) {
Object ret = f.invoke(start, first());
for(ISeq s = next(); s != null; s = s.next()) {
for(PersistentSortedList s = next(); s != null; s = s.next()) {
if (RT.isReduced(ret)) return ((IDeref)ret).deref();
ret = f.invoke(ret, s.first());
}
@@ -88,12 +114,10 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
return ret;
}
@Override
public Object first() {
return peek();
}
@Override
public PersistentSortedList next() {
if(_count == 0){
return null;
@@ -109,6 +133,18 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
return new PersistentSortedList(meta(), nextImpl, _count - 1);
}
// Things that i did not want to implement.
private List reify(){
return Collections.unmodifiableList(new ArrayList(this));
}
@Override
public ISeq more() {
ISeq s = next();
return s == null ? PersistentSortedList.EMPTY : s;
}
@Override
public Obj withMeta(IPersistentMap meta) {
if(meta != meta()){
@@ -116,5 +152,151 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu
}
return this;
}
@Override
public int hasheq() {
if(_hasheq == 0){
_hasheq = Murmur3.hashOrdered(this);
}
return _hasheq;
}
@Override
public ISeq seq() {
return count() == 0 ? null : (ISeq) this;
}
@Override
public int compareTo(Object o) {
return 0;
}
@Override
public int size() {
return count();
}
@Override
public boolean isEmpty() {
return seq() == null;
}
@Override
public boolean contains(Object o) {
return impl.containsKey(o);
}
@Override
public Object[] toArray() {
return RT.seqToArray(seq());
}
@Override
public boolean add(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int i, Collection collection) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public Object get(int index) {
return RT.nth(this, index);
}
@Override
public Object set(int i, Object o) {
throw new UnsupportedOperationException();
}
@Override
public void add(int i, Object o) {
throw new UnsupportedOperationException();
}
@Override
public Object remove(int i) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(Object o) {
// TODO: make this function fast by using the underlying sorted set. This function should be constant.
ISeq s = seq();
for(int i = 0; s != null; s = s.next(), i++) {
if(Util.equiv(s.first(), o)){
return i;
}
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
// TODO: make this function fast by using the underlying sorted set. This function should be constant.
return reify().lastIndexOf(o);
}
@Override
public ListIterator listIterator() {
return reify().listIterator();
}
@Override
public ListIterator listIterator(int index) {
return reify().listIterator(index);
}
@Override
public List subList(int fromIndex, int toIndex) {
return reify().subList(fromIndex, toIndex);
}
@Override
public boolean retainAll(Collection collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection collection) {
for(Object o : collection) {
if(!contains(o)){
return false;
}
}
return true;
}
@Override
public Object[] toArray(Object[] objects) {
return RT.seqToPassedArray(seq(), objects);
}
@Override
public Iterator iterator() {
return new SeqIterator(this);
}
}