139 lines
4.7 KiB
Plaintext
139 lines
4.7 KiB
Plaintext
(do
|
|
;; ===========================================================================
|
|
;; 1. DEFINITIONEN
|
|
;; ===========================================================================
|
|
|
|
;; ---------------------------------------------------------------------------
|
|
;; Factory: create-wma
|
|
;; Berechnet WMA. Wartet, bis das Fenster voll ist.
|
|
;; Phase 1: Warten (< len)
|
|
;; Phase 2: Init (= len) -> Loop berechnung
|
|
;; Phase 3: Slide (> len) -> O(1) berechnung
|
|
;; ---------------------------------------------------------------------------
|
|
(def create-wma
|
|
(fn [len]
|
|
(do
|
|
(def prev-w-sum 0.0)
|
|
(def prev-s-sum 0.0)
|
|
(def weight-div (/ (* len (+ len 1)) 2))
|
|
|
|
(fn [src]
|
|
(do
|
|
(def cnt (count src))
|
|
|
|
;; PHASE 1: Nicht genug Daten
|
|
(if (< cnt len)
|
|
NaN
|
|
|
|
;; Genug Daten vorhanden
|
|
(if (= cnt len)
|
|
;; PHASE 2: Initialisierung (Das Fenster ist gerade voll geworden)
|
|
;; Wir müssen einmalig die Basis-Summen berechnen.
|
|
(do
|
|
(def init-w 0.0)
|
|
(def init-s 0.0)
|
|
|
|
;; Loop über die Elemente 0 bis len-1
|
|
((fn [i]
|
|
(if (< i len)
|
|
(do
|
|
(def val (get src i))
|
|
;; Gewichtung: Index 0 ist das neueste -> Gewicht 'len'
|
|
(assign init-w (+ init-w (* (- len i) val)))
|
|
(assign init-s (+ init-s val))
|
|
(recur (+ i 1)))
|
|
)) 0)
|
|
|
|
;; State speichern
|
|
(assign prev-w-sum init-w)
|
|
(assign prev-s-sum init-s)
|
|
(/ init-w weight-div))
|
|
|
|
;; PHASE 3: Sliding Window (O(1))
|
|
;; Wir haben bereits einen gültigen State aus dem vorherigen Schritt.
|
|
(do
|
|
(def val-new (get src 0)) ; Neuster Wert
|
|
(def val-out (get src len)) ; Wert der rausfällt
|
|
|
|
;; Update Formeln
|
|
(def w-sum (+ prev-w-sum (- (* len val-new) prev-s-sum)))
|
|
(def s-sum (+ (- prev-s-sum val-out) val-new))
|
|
|
|
;; State speichern
|
|
(assign prev-w-sum w-sum)
|
|
(assign prev-s-sum s-sum)
|
|
(/ w-sum weight-div))
|
|
)
|
|
)
|
|
))
|
|
)))
|
|
|
|
;; --- HMA Factory ---
|
|
(def create-hma
|
|
(fn [len]
|
|
(do
|
|
(def half-len (round (/ len 2)))
|
|
(def sqrt-len (round (sqrt len)))
|
|
|
|
(def wma-half (create-wma half-len))
|
|
(def wma-full (create-wma len))
|
|
(def wma-smooth (create-wma sqrt-len))
|
|
|
|
(def diff-series (new-series [[:val :Float]]))
|
|
|
|
(fn [src]
|
|
(do
|
|
(def v1 (wma-half src))
|
|
(def v2 (wma-full src))
|
|
|
|
;; WICHTIG: Wir dürfen erst weitermachen, wenn BEIDE WMAs gültig sind.
|
|
;; Da v2 das längere Fenster (len) braucht, diktiert es den Takt.
|
|
(def diff (- (* 2 v1) v2))
|
|
(if (not (is-NaN diff))
|
|
(add-item diff-series {:val diff}))
|
|
|
|
;; Glättung auf dem Resultat
|
|
(wma-smooth (.val diff-series))
|
|
))
|
|
)))
|
|
|
|
;; --- Repeat Macro ---
|
|
(defmacro repeat [n body]
|
|
`((fn [cnt]
|
|
(if (> cnt 0)
|
|
(do
|
|
~body
|
|
(recur (- cnt 1)))))
|
|
~n))
|
|
|
|
;; ===========================================================================
|
|
;; 2. SIMULATION
|
|
;; ===========================================================================
|
|
|
|
(def hma-length 250)
|
|
(def simulation-steps 5000)
|
|
|
|
(def hma-calc (create-hma hma-length))
|
|
(def prices (new-series [[:close :Float]]))
|
|
(def current-price 100.0)
|
|
|
|
(print "Step | Price | HMA(14)")
|
|
(print "-----|----------|----------")
|
|
|
|
(repeat simulation-steps
|
|
(do
|
|
;; Random Walk
|
|
(assign current-price (+ current-price (- (random) 0.5)))
|
|
(add-item prices {:close current-price})
|
|
|
|
;; Berechnung
|
|
;; Nutzung von Member Access (.close), da es eine Record-Series ist
|
|
(def hma-val (hma-calc (.close prices)))
|
|
|
|
;; Ausgabe
|
|
(if (not (is-NaN hma-val))
|
|
(print (count prices) " |" current-price " | " hma-val)
|
|
)
|
|
)
|
|
)
|
|
) |