going somewhere
This commit is contained in:
1 parent
b7af65b705
commit
d5c6360f88
12 files changed
+160
-25
No files matched your search
Regular → Executable
File mode changed.
+2
-3
@@ -4,7 +4,6 @@
|
|||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||||
|
|
||||||
|
|
||||||
:resource-paths ["resources"
|
:resource-paths ["resources"
|
||||||
"target/cljsbuild"]
|
"target/cljsbuild"]
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@
|
|||||||
[orchestra "2017.11.12-1"]
|
[orchestra "2017.11.12-1"]
|
||||||
[cheshire "5.8.0"]
|
[cheshire "5.8.0"]
|
||||||
[com.stuartsierra/frequencies "0.1.0"]
|
[com.stuartsierra/frequencies "0.1.0"]
|
||||||
|
[rm-hull/infix "0.3.3"]
|
||||||
|
|
||||||
;; wui
|
;; wui
|
||||||
[ring-server "0.5.0"]
|
[ring-server "0.5.0"]
|
||||||
@@ -126,8 +126,7 @@
|
|||||||
:sass {:source-paths ["src/sass"]
|
:sass {:source-paths ["src/sass"]
|
||||||
:target-path "resources/public/css"}
|
:target-path "resources/public/css"}
|
||||||
|
|
||||||
:profiles {:dev {:repl-options {:init-ns skirmish.wui.repl
|
:profiles {:dev {
|
||||||
:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}
|
|
||||||
:java-source-paths ["src/java"]
|
:java-source-paths ["src/java"]
|
||||||
|
|
||||||
:dependencies [[midje "1.9.9"]
|
:dependencies [[midje "1.9.9"]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
;; Specify which middleware to use, it will default to :chan.
|
;; Specify which middleware to use, it will default to :chan.
|
||||||
:middleware :kafka
|
:middleware :chan
|
||||||
|
|
||||||
;; If set to true, orchestra will instrument all the spec'ed functions
|
;; If set to true, orchestra will instrument all the spec'ed functions
|
||||||
:instrument-spec true
|
:instrument-spec true
|
||||||
|
|
||||||
:datomic
|
:datomic
|
||||||
{:transactor-url "datomic:free://localhost:4334/skirmish.ledger"}
|
{:transactor-url "datomic:free://localhost:4334/skirmish.ledger?password=datomicpassword"}
|
||||||
|
|
||||||
;; all the kafka configuration goes bellow.
|
;; all the kafka configuration goes bellow.
|
||||||
:kafka
|
:kafka
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
:max-body 524288 ;; 512kb, small but enough
|
:max-body 524288 ;; 512kb, small but enough
|
||||||
:max-ws 524288
|
:max-ws 524288
|
||||||
:default-sec-id :dapm
|
:default-sec-id :dapm
|
||||||
:datomic {:transactor-url "datomic:free://localhost:4334/skirmish.broker"}}
|
:datomic {:transactor-url "datomic:free://localhost:4334/skirmish.broker?password=datomicpassword"}}
|
||||||
|
|
||||||
:wui
|
:wui
|
||||||
{:port #long #or [#env WUI_PORT 3000]}}
|
{:port #long #or [#env WUI_PORT 3000]}}
|
||||||
|
|||||||
@@ -8,19 +8,16 @@
|
|||||||
[skirmish.routes.core :as routes]
|
[skirmish.routes.core :as routes]
|
||||||
[clj-http.client :as http-client]))
|
[clj-http.client :as http-client]))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-amount-for-new-user [seed]
|
(defn generate-amount-for-new-user [seed]
|
||||||
(let [random (new java.util.Random seed)
|
(let [random (new java.util.Random seed)
|
||||||
random-fn #(. random nextInt 20000)]
|
random-fn #(. random nextInt 20000)]
|
||||||
(* 100 (reduce + (take 100 (repeatedly random-fn))))))
|
(* 100 (reduce + (take 100 (repeatedly random-fn))))))
|
||||||
|
|
||||||
|
|
||||||
(defn create-account [account-id sec-id]
|
(defn create-account [account-id sec-id]
|
||||||
#:skirmish.broker.account{:id account-id
|
#:skirmish.broker.account{:id account-id
|
||||||
:sec-id sec-id
|
:sec-id sec-id
|
||||||
:private-key (str account-id)})
|
:private-key (str account-id)})
|
||||||
|
|
||||||
|
|
||||||
(defn create-user-account [seed default-sec-id]
|
(defn create-user-account [seed default-sec-id]
|
||||||
(let [url (routes/get-path-for :ledger/security {:sec-id (name default-sec-id)})
|
(let [url (routes/get-path-for :ledger/security {:sec-id (name default-sec-id)})
|
||||||
account-id (java.util.UUID/randomUUID)
|
account-id (java.util.UUID/randomUUID)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
(concat accounts-schema)))
|
(concat accounts-schema)))
|
||||||
|
|
||||||
(defn create-connection [uri]
|
(defn create-connection [uri]
|
||||||
(let [new-db? (d/create-database uri)
|
(let [_ (d/create-database uri)
|
||||||
conn (d/connect uri)]
|
conn (d/connect uri)]
|
||||||
@(d/transact conn schema)
|
@(d/transact conn schema)
|
||||||
conn))
|
conn))
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
exchange-apis (create-exchange-apis-for config securities-api)]
|
exchange-apis (create-exchange-apis-for config securities-api)]
|
||||||
(if (= (count target-fns) 1)
|
(if (= (count target-fns) 1)
|
||||||
((first target-fns) config securities-api exchange-apis)
|
((first target-fns) config securities-api exchange-apis)
|
||||||
(run-all-targets-in-separate-threads target-fns config securities-api exchange-apis))))
|
(run-all-targets-in-separate-threads target-fns config securities-api exchange-apis))
|
||||||
|
(skirmish.util/block-thread)))
|
||||||
|
|
||||||
(defn -main [& argv]
|
(defn -main [& argv]
|
||||||
(let [config (-> "config.edn" clojure.java.io/resource read-config)
|
(let [config (-> "config.edn" clojure.java.io/resource read-config)
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
(if (seq target-fns)
|
(if (seq target-fns)
|
||||||
(run-all-targets target-fns config)
|
(run-all-targets target-fns config)
|
||||||
(do
|
(do
|
||||||
(timbre/info argv)
|
(timbre/warn argv)
|
||||||
(timbre/info "target" target-fns "not found")
|
(timbre/warn "target" target-fns "not found")
|
||||||
(timbre/info "all known targets are...")
|
(timbre/warn "all known targets are...")
|
||||||
(timbre/info (keys targets))))))
|
(timbre/warn (keys targets))))))
|
||||||
@@ -82,7 +82,12 @@
|
|||||||
:db/ident :skirmish.security/interest-rate
|
:db/ident :skirmish.security/interest-rate
|
||||||
:db/valueType :db.type/long
|
:db/valueType :db.type/long
|
||||||
:db/cardinality :db.cardinality/one
|
:db/cardinality :db.cardinality/one
|
||||||
:db/doc "The interest-rate payed by the security as a multiple of 0.01% (100 is 1% interest rate)."}])
|
:db/doc "The daily interest-rate payed by the security as a multiple of 0.01% (100 is 1% interest rate)."}
|
||||||
|
{
|
||||||
|
:db/ident :skirmish.security/inflation
|
||||||
|
:db/valueType :db.type/long
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The daily inflation as a multiple of 0.01% (100 is 1%)."}])
|
||||||
|
|
||||||
(def ledger-schema
|
(def ledger-schema
|
||||||
[
|
[
|
||||||
@@ -120,7 +125,8 @@
|
|||||||
:emitter "dapm private key"
|
:emitter "dapm private key"
|
||||||
:number-of-decimal 2
|
:number-of-decimal 2
|
||||||
:symbol "რ"
|
:symbol "რ"
|
||||||
:interest-rate 10}
|
:interest-rate (* 100 10)
|
||||||
|
:inflation (* 100 9)}
|
||||||
apbm #:skirmish.security{:sec-id :apbm
|
apbm #:skirmish.security{:sec-id :apbm
|
||||||
:name "apache beam"
|
:name "apache beam"
|
||||||
:type :equity
|
:type :equity
|
||||||
|
|||||||
@@ -12,12 +12,86 @@
|
|||||||
[taoensso.timbre :as timbre]
|
[taoensso.timbre :as timbre]
|
||||||
[compojure.core :as compojure]
|
[compojure.core :as compojure]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
|
[infix.macros :refer [infix]]
|
||||||
[ring.middleware.cors :refer [wrap-cors]]))
|
[ring.middleware.cors :refer [wrap-cors]]))
|
||||||
|
|
||||||
;; the ledger is the central
|
;; the ledger is the central
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn compute-simple-face-value [amount daily-interest-rate deposit-date value-date]
|
||||||
|
(let [min-in-milliseconds (infix 60 * 1000)
|
||||||
|
minute-interest-rate (infix daily-interest-rate / (24 * 60. * 10000.))
|
||||||
|
ite (quot (- (. value-date getTime) (. deposit-date getTime)) min-in-milliseconds)
|
||||||
|
base (infix 1 + minute-interest-rate)]
|
||||||
|
(infix amount * base ** ite)))
|
||||||
|
|
||||||
|
(defn- in-interval? [[_ start end] x]
|
||||||
|
(let [x-time (. x getTime)]
|
||||||
|
(and (<= (. start getTime) x-time)
|
||||||
|
(< x-time (. end getTime)))))
|
||||||
|
|
||||||
|
(defn- larger-then-interval? [[ _ start end] x]
|
||||||
|
(and (<= (. x getTime) (. end getTime))
|
||||||
|
(<= (. x getTime) (. start getTime))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- split-interest-rate-intervals [interest-rates-intervals deposit-date value-date]
|
||||||
|
(let [xf (comp (drop-while #((comp not in-interval?) % deposit-date))
|
||||||
|
(take-while #((comp not larger-then-interval?) % value-date)))
|
||||||
|
ret (into [] xf interest-rates-intervals)
|
||||||
|
ret (assoc-in ret [0 1] deposit-date)
|
||||||
|
ret (assoc-in ret [(-> ret count dec) 2] value-date)]
|
||||||
|
ret))
|
||||||
|
|
||||||
|
(defn- find-interest-rate-for [interest-rates-intervals d]
|
||||||
|
(if (in-interval? (first interest-rates-intervals) d)
|
||||||
|
(ffirst interest-rates-intervals)
|
||||||
|
(recur (rest interest-rates-intervals) d)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn split-interest-rates [interest-rates deposit-date value-date]
|
||||||
|
(let [interest-rates (into [[0 (new java.util.Date 0)]] interest-rates)
|
||||||
|
interest-rates (conj interest-rates [0 (new java.util.Date Long/MAX_VALUE)])
|
||||||
|
interest-rates-intervals (partition 2 1 interest-rates)
|
||||||
|
interest-rates-intervals (map (juxt ffirst (comp second first) (comp second second)) interest-rates-intervals)]
|
||||||
|
(if (= deposit-date value-date)
|
||||||
|
[[(find-interest-rate-for interest-rates-intervals deposit-date) deposit-date value-date]]
|
||||||
|
(split-interest-rate-intervals interest-rates-intervals deposit-date value-date))))
|
||||||
|
|
||||||
|
(defn compute-face-value [amount interest-rates deposit-date value-date]
|
||||||
|
(loop [interest-rates (split-interest-rates interest-rates deposit-date value-date)
|
||||||
|
amount amount]
|
||||||
|
(let [[interest-rate start end] (first interest-rates)
|
||||||
|
amount (compute-simple-face-value amount interest-rate start end)]
|
||||||
|
(if (empty? (rest interest-rates))
|
||||||
|
(long amount)
|
||||||
|
(recur (rest interest-rates) amount)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn get-amount-in-account [db account-id]
|
||||||
|
(let [[amount sec-id date] (d/q '[:find [?amount ?sec ?v]
|
||||||
|
:in $ ?account-id
|
||||||
|
:where [?e :skirmish.ledger/owner-public-key ?account-id]
|
||||||
|
[?e :skirmish.ledger/amount ?amount ?tx]
|
||||||
|
[?e :skirmish.ledger/sec ?sec]
|
||||||
|
[?tx :db/txInstant ?v]] db account-id)
|
||||||
|
history (d/history db)
|
||||||
|
interest-rates (d/q '[:find ?interest-rate ?v
|
||||||
|
:in $ ?eid
|
||||||
|
:where [?eid :skirmish.security/interest-rate ?interest-rate ?tx]
|
||||||
|
[?tx :db/txInstant ?v]]
|
||||||
|
history sec-id)
|
||||||
|
face-value (compute-face-value amount
|
||||||
|
date
|
||||||
|
(sort-by second interest-rates)
|
||||||
|
(new java.util.Date))]
|
||||||
|
{:value face-value
|
||||||
|
:sec-id sec-id
|
||||||
|
:account-public-key (:skirmish.ledger/owner-public-key 333)}))
|
||||||
|
|
||||||
;; an :account-id is the public key of a
|
;; an :account-id is the public key of a
|
||||||
;; an :account-secret is an :acount-id private key
|
;; an :account-secret is an :account-id private key
|
||||||
|
|
||||||
(defn get-account-body [request account sec]
|
(defn get-account-body [request account sec]
|
||||||
(if (nil? sec)
|
(if (nil? sec)
|
||||||
@@ -29,7 +103,6 @@
|
|||||||
ret {:account beautify-account :sec-url sec-url}]
|
ret {:account beautify-account :sec-url sec-url}]
|
||||||
(build-response request ret))))
|
(build-response request ret))))
|
||||||
|
|
||||||
|
|
||||||
(defn get-account [conn]
|
(defn get-account [conn]
|
||||||
"Returns the value of an account."
|
"Returns the value of an account."
|
||||||
(fn [{{account-id :account-id} :route-params :as request}]
|
(fn [{{account-id :account-id} :route-params :as request}]
|
||||||
@@ -157,7 +230,7 @@
|
|||||||
create securities.
|
create securities.
|
||||||
|
|
||||||
payload
|
payload
|
||||||
[:amount :acount]"
|
[:amount :account]"
|
||||||
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
||||||
(try+
|
(try+
|
||||||
(let [emit-request (-> body get-body (get-emit-securities-request (keyword sec-id-str)))]
|
(let [emit-request (-> body get-body (get-emit-securities-request (keyword sec-id-str)))]
|
||||||
@@ -171,7 +244,7 @@
|
|||||||
(let [sec-id->url #(routes/get-path-for :ledger/account {:account-id (name %)})
|
(let [sec-id->url #(routes/get-path-for :ledger/account {:account-id (name %)})
|
||||||
to-security-description #(hash-map :account-public-key % :url (sec-id->url %))
|
to-security-description #(hash-map :account-public-key % :url (sec-id->url %))
|
||||||
xf (comp cat (map to-security-description))
|
xf (comp cat (map to-security-description))
|
||||||
securities-info (sequence xf accounts)];;
|
securities-info (sequence xf accounts)]
|
||||||
{:accounts securities-info}))
|
{:accounts securities-info}))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
(ns skirmish.util
|
(ns skirmish.util
|
||||||
(:require [clojure.core.async :as async])
|
(:require [clojure.core.async :as async])
|
||||||
(:import (skirmish PersistentSortedList)))
|
(:import [ skirmish PersistentSortedList]))
|
||||||
|
|
||||||
(defn sorted-list [& keys]
|
(defn sorted-list [& keys]
|
||||||
(PersistentSortedList/create (seq keys)))
|
(PersistentSortedList/create (seq keys)))
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
(defn page [state]
|
(defn page [state]
|
||||||
[:div
|
[:div
|
||||||
[:section.section
|
[:section.section
|
||||||
|
[:div.columns
|
||||||
[:div.container
|
[:div.container
|
||||||
[:img {:src "/images/amsterdam.svg"}]
|
[:img {:src "/images/amsterdam.svg"}]]]
|
||||||
|
[:div.columns.is-centered
|
||||||
[login state]]]])
|
[login state]]]])
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
(ns skirmish.ledger.core-test
|
||||||
|
(:require [clojure.test :refer :all])
|
||||||
|
(:require [skirmish.ledger.core :refer [get-amount-in-account]]))
|
||||||
|
|
||||||
|
(deftest get-amount-in-account-test)
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
[skirmish.ledger.core :refer :all]
|
[skirmish.ledger.core :refer :all]
|
||||||
[skirmish.rest.util :refer [edn->stream]]
|
[skirmish.rest.util :refer [edn->stream]]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
|
[infix.macros :refer [infix]]
|
||||||
[skirmish.ledger.accounts :refer [create-connection schema]]))
|
[skirmish.ledger.accounts :refer [create-connection schema]]))
|
||||||
|
|
||||||
(defn spec-check [spec]
|
(defn spec-check [spec]
|
||||||
@@ -198,9 +199,59 @@
|
|||||||
((get-account conn) req) => (spec-check ::status-404))))
|
((get-account conn) req) => (spec-check ::status-404))))
|
||||||
|
|
||||||
|
|
||||||
|
(facts "about interest computation"
|
||||||
|
(fact "about very basic interest rates"
|
||||||
|
(let [amount 1000
|
||||||
|
interest-rate (* 10 100) ;; daily 10% interest rates
|
||||||
|
negative-interest-rate (- interest-rate)
|
||||||
|
start #inst"2020-09-05T00:00:00.000-00:00"
|
||||||
|
start+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||||
|
start+2d #inst"2020-09-07T00:00:00.000-00:00"]
|
||||||
|
(compute-simple-face-value amount interest-rate start start) => (roughly amount)
|
||||||
|
(compute-simple-face-value amount interest-rate start start+1d) => (roughly 1105.1670808)
|
||||||
|
(compute-simple-face-value amount interest-rate start start+2d) => (roughly 1221.3942766)
|
||||||
|
(compute-simple-face-value amount negative-interest-rate start start+2d) => (roughly 818.7250672)
|
||||||
|
(compute-simple-face-value amount 0 start start+2d) => (roughly amount)))
|
||||||
|
(fact "split-interest-rates"
|
||||||
|
(let [d-1d #inst"2020-09-04T00:00:00.000-00:00"
|
||||||
|
d-½d #inst"2020-09-04T12:00:00.000-00:00"
|
||||||
|
d #inst"2020-09-05T00:00:00.000-00:00"
|
||||||
|
d+½d #inst"2020-09-05T12:00:00.000-00:00"
|
||||||
|
d+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||||
|
d+1½d #inst"2020-09-06T12:00:00.000-00:00"
|
||||||
|
d+2d #inst"2020-09-07T00:00:00.000-00:00"
|
||||||
|
d+2½d #inst"2020-09-07T12:00:00.000-00:00"
|
||||||
|
d+3d #inst"2020-09-08T00:00:00.000-00:00"
|
||||||
|
d+3½d #inst"2020-09-08T12:00:00.000-00:00";;
|
||||||
|
interest-rates [[10 d] [15 d+1d] [20 d+2d]]]
|
||||||
|
(split-interest-rates interest-rates d+½d d+3d) => [[10 d+½d d+1d] [15 d+1d d+2d] [20 d+2d d+3d]]
|
||||||
|
(split-interest-rates interest-rates d+3d d+3½d) => [[20 d+3d d+3½d]]
|
||||||
|
(split-interest-rates interest-rates d-1d d-½d) => [[0 d-1d d-½d]]
|
||||||
|
(split-interest-rates interest-rates d d+½d) => [[10 d d+½d]]
|
||||||
|
(split-interest-rates interest-rates d+2½d d+2½d) => [[20 d+2½d d+2½d]]))
|
||||||
|
(fact "compute-face-value"
|
||||||
|
(let [d-1d #inst"2020-09-04T00:00:00.000-00:00"
|
||||||
|
d-½d #inst"2020-09-04T12:00:00.000-00:00"
|
||||||
|
d #inst"2020-09-05T00:00:00.000-00:00"
|
||||||
|
d+½d #inst"2020-09-05T12:00:00.000-00:00"
|
||||||
|
d+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||||
|
d+1½d #inst"2020-09-06T12:00:00.000-00:00"
|
||||||
|
d+2d #inst"2020-09-07T00:00:00.000-00:00"
|
||||||
|
d+2½d #inst"2020-09-07T12:00:00.000-00:00"
|
||||||
|
d+3d #inst"2020-09-08T00:00:00.000-00:00"
|
||||||
|
d+3½d #inst"2020-09-08T12:00:00.000-00:00"
|
||||||
|
amount 10000000
|
||||||
|
interest-rates [[10 d] [15 d+1d] [20 d+2d]]]
|
||||||
|
(compute-face-value amount interest-rates d+½d d+½d) => amount
|
||||||
|
(compute-face-value amount interest-rates d-1d d-½d) => amount
|
||||||
|
(compute-face-value amount interest-rates d-1d d+3d) => 10045101)))
|
||||||
|
|
||||||
|
;(split-interest-rates interest-rates d+3d d+½d) => [[10 d d+½d]])))
|
||||||
|
|
||||||
|
|
||||||
|
;; TOD
|
||||||
|
|
||||||
|
|
||||||
;; TODO
|
|
||||||
|
|
||||||
;; 4. transfer sec from one account to the other.
|
;; 4. transfer sec from one account to the other.
|
||||||
;; 5. account for interest
|
|
||||||
|
|
||||||
Reference in new issue
Block a user