Skip to content

Commit

Permalink
nacktest2 working again
Browse files Browse the repository at this point in the history
  • Loading branch information
awb99 committed Oct 10, 2024
1 parent b5e98d8 commit 8b65d8c
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 254 deletions.
4 changes: 0 additions & 4 deletions dev/src/dev/backtest/backtest.clj
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,8 @@ bar-ds
; :exit-idx
]))


; | :side | :qty | :entry-price | :exit-price | :entry-date | :exit-date | :reason |
; |--------+------+--------------+-------------------+----------------------+----------------------+--------------|
; | :long | 1.0 | 100 | 101.0 | 2024-09-02T00:00:00Z | 2024-09-03T00:00:00Z | :profit-prct |
; | :long | 1.0 | 100 | 101.0 | 2024-09-05T00:00:00Z | 2024-09-07T00:00:00Z | :profit-prct |
; | :short | 1.0 | 100 | 99.00990099009901 | 2024-09-08T00:00:00Z | 2024-09-09T00:00:00Z | :profit-prct |



106 changes: 64 additions & 42 deletions dev/src/dev/backtest/rule.clj
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
(ns dev.backtest.rule
(:require
[tick.core :as t]
[quanta.trade.entry-signal.rule :as rule]))
[quanta.trade.entry-signal.core :as rule]))

(def m (rule/create-entrysignal-manager
{:asset "EUR/USD"
:entry {:type :fixed-qty :fixed-qty 1.0}
:exit [{:type :profit-prct :prct 1.0}
{:type :profit-prct :prct 5.0}]}))
;; => #'dev.backtest.rule/m


m
;; => {:positions #<Atom@55aa0710: {}>,
;; => {:positions #<Atom@1938e715: {}>,
;; :asset "EUR/USD",
;; :entrysize-fn #function[quanta.trade.entry-signal.rule.entry/eval40973/fn--40975/fn--40977],
;; :exit-rules creating profit-prct exit rule opts: {:type :profit-prct, :prct 1.0}
;; creating profit-prct exit rule opts: {:type :profit-prct, :prct 5.0}
;; (#function[quanta.trade.entry-signal.rule.exit/eval49683/fn--49685/fn--49688]
;; #function[quanta.trade.entry-signal.rule.exit/eval49683/fn--49685/fn--49688])}
;; :entrysize-fn #function[quanta.trade.entry-signal.entry.core/eval8847/fn--8849/fn--8851],
;; :exit-rules
;; (#function[quanta.trade.entry-signal.exit.config/eval9125/fn--9127/fn--9130]
;; #function[quanta.trade.entry-signal.exit.config/eval9125/fn--9127/fn--9130])}


(rule/on-position-open m {:id 5
:asset "EUR/USD"
Expand All @@ -26,6 +28,38 @@ m
:entry-date (t/instant "2023-01-03T00:00:00Z")
:qty 100000
})
;; => {5
;; {:position
;; {:id 5,
;; :asset "EUR/USD",
;; :side :long,
;; :entry-price 1.1,
;; :entry-idx 107,
;; :entry-date #time/instant "2023-01-03T00:00:00Z",
;; :qty 100000},
;; :manager
;; {:rules
;; ({:position
;; {:id 5,
;; :asset "EUR/USD",
;; :side :long,
;; :entry-price 1.1,
;; :entry-idx 107,
;; :entry-date #time/instant "2023-01-03T00:00:00Z",
;; :qty 100000},
;; :level 1.1110000000000002,
;; :label :profit-prct}
;; {:position
;; {:id 5,
;; :asset "EUR/USD",
;; :side :long,
;; :entry-price 1.1,
;; :entry-idx 107,
;; :entry-date #time/instant "2023-01-03T00:00:00Z",
;; :qty 100000},
;; :level 1.1550000000000002,
;; :label :profit-prct})}}}

;; => {5
;; {:position
;; {:id 5,
Expand All @@ -37,13 +71,13 @@ m
;; :qty 100000},
;; :position-fn #function[quanta.trade.entry-signal.rule.exit/position-rules/fn--49854]}}

(rule/check-exit m {:ds nil
:row {:high 1.10 :low 1.09 :idx 1000 :date (t/instant)}})
(rule/check-exit m {:high 1.10 :low 1.09 :idx 1000 :date (t/instant)})
;; => ()

;; ()

(rule/check-exit m {:ds nil
:row {:high 1.12 :low 1.09 :idx 1001 :date (t/instant)}})
;; ({:entry-date #time/instant "2023-01-03T00:00:00Z",
(rule/check-exit m {:high 1.12 :low 1.09 :idx 1001 :date (t/instant)})
;; => ({:entry-date #time/instant "2023-01-03T00:00:00Z",
;; :entry-price 1.1,
;; :reason :profit-prct,
;; :exit-idx 1001,
Expand All @@ -52,41 +86,29 @@ m
;; :qty 100000,
;; :exit-price 1.1110000000000002,
;; :asset "EUR/USD",
;; :exit-date #time/instant "2024-10-07T04:14:31.986421257Z"})
;; :exit-date #time/instant "2024-10-10T13:08:48.806873734Z"})

(rule/check-exit m {:ds nil
:row {:high 1.20 :low 1.09 :idx 1002 :date (t/instant)}})
;; ({:id 5,
;; :asset "EUR/USD",
(rule/check-exit m {:high 1.20 :low 1.09 :idx 1002 :date (t/instant)})
;; => ({:entry-date #time/instant "2023-01-03T00:00:00Z",
;; :entry-price 1.1,
;; :reason :profit-prct,
;; :exit-idx 1002,
;; :id 5,
;; :side :long,
;; :qty 100000,
;; :exit-price 1.1110000000000002,
;; :exit-date #time/instant "2024-10-07T04:05:51.775349999Z"})

(rule/check-exit m {:ds nil
:row {:high 1.20 :low 1.09 :idx 1002
:close 1.07 :date (t/instant) :entry :long}})

;; ({:id 5,
;; :asset "EUR/USD",
;; :exit-date #time/instant "2024-10-10T13:08:58.455516934Z"})

(rule/check-exit m {:high 1.20 :low 1.09 :idx 1002
:close 1.07 :date (t/instant) :entry :long})
;; => ({:entry-date #time/instant "2023-01-03T00:00:00Z",
;; :entry-price 1.1,
;; :reason :profit-prct,
;; :exit-idx 1002,
;; :id 5,
;; :side :long,
;; :qty 100000,
;; :exit-price 1.1110000000000002,
;; :exit-date #time/instant "2024-10-07T04:06:35.945787055Z"})



(def row {:close 100.0 :entry :long
:idx 107 :date })

(eventually-entry-position "QQQ" [:fixed-qty 3.1] row)
(eventually-entry-position "QQQ" [:fixed-amount 15000.0] row)




(def m-bad (esm/create-entrysignal-manager
{:entry nil
:exit [{:type :glorified-dummy :a 1.0}]}))

m-bad
;; :asset "EUR/USD",
;; :exit-date #time/instant "2024-10-10T13:09:56.032519040Z"})
4 changes: 2 additions & 2 deletions dev/src/dev/exit/trailing_stop.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns dev.exit.trailing-stop
(:require
[quanta.trade.entry-signal.rule.exit2 :refer [check-exit]]
[quanta.trade.entry-signal.rule.exit-config :refer [exit-rule]]))
[quanta.trade.entry-signal.exit.exit2 :refer [check-exit]]
[quanta.trade.entry-signal.exit.exit-config :refer [exit-rule]]))

(def configured-rule (exit-rule {:type :trailing-stop-offset
:col :atr}))
Expand Down
8 changes: 2 additions & 6 deletions src/quanta/trade/backtest/from_entry.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,8 @@
r (range n)
ds-idx (tc/add-column ds :idx r)]
(loop [idx 0]
(let [ds-until-idx (tc/select-rows ds-idx (range 0 (inc idx)))
row (row-at ds-idx idx)
output {;:idx idx
:data {:row row
:ds nil ; ds-until-idx
}}
(let [row (row-at ds-idx idx)
output {:data row}
entry (:entry row)
output (case entry
:long (assoc output :entry-signal entry)
Expand Down
2 changes: 1 addition & 1 deletion src/quanta/trade/backtest2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[tablecloth.api :as tc]
[missionary.core :as m]
[quanta.trade.commander :as cmd]
[quanta.trade.entry-signal.rule :as rule]
[quanta.trade.entry-signal.core :as rule]
[quanta.trade.backtest.commander :refer [create-position-commander]]
[quanta.trade.backtest.from-entry :refer [from-algo-ds]]))

Expand Down
75 changes: 75 additions & 0 deletions src/quanta/trade/entry_signal/core.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
(ns quanta.trade.entry-signal.core
(:require
[quanta.trade.entry-signal.entry.core :as entry]
[quanta.trade.entry-signal.exit.config :refer [exit-rule]]
[quanta.trade.entry-signal.exit.position :as exit])
(:import
[quanta.trade.entry_signal.exit.position MultipleRules]))

(defn create-entrysignal-manager [{:keys [asset entry exit]}]
{:positions (atom {})
:asset asset
:entrysize-fn (entry/positionsize2 entry)
:exit-rules (map exit-rule exit)})

;; entry

(defn create-entry [this data]
(println "rule/create-entry: " data)
(entry/create-position this data))

; on position open/close

(defn create-exit-manager-for-position
"create a exit-fn for one position.
this gets run on each bar, while the positon is open"
[rules position]
;(println "creating exit-rules for position: " position)
;(println "exit rules: " rules)
(let [position-rules (map #(% position) rules)]
(MultipleRules. position-rules)))

(defn on-position-open
"on-position-open is an event that gets emitted by trade-commander.
we need to start new exit-rules for a new position here."
[{:keys [exit-rules positions]} position]
(assert exit-rules "rule manager state needs to have :exit-rules")
(println "rule/on-position-open: " position)
(swap! positions assoc
(:id position)
{:position position
:manager (create-exit-manager-for-position exit-rules position)}))

(defn on-position-close [{:keys [positions]} position]
(println "rule/on-position-close: " position)
(swap! positions dissoc (:id position)))

(defn check-exit-position [{:keys [position manager]} row]
;(println "check-exit-position: " position)
;; {:id 5, :asset EUR/USD, :side :long,
;; :entry-price 1.1, :qty 100000}
(when-let [exit (exit/check-exit manager row)] ; [:profit-prct 1.1110000000000002]
(let [[reason exit-price] exit
{:keys [id asset side entry-price entry-date qty]} position
{:keys [idx date]} row]
{:id id
:asset asset
:side side
:qty qty
:entry-price entry-price
:entry-date entry-date
; exit
:reason reason
:exit-idx idx
:exit-price exit-price
:exit-date date})))

(defn check-exit [{:keys [positions]} row]
(println "rule/check-exit: " row)
(->> (vals @positions)
(map #(check-exit-position % row))
(remove nil?)))




Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns quanta.trade.entry-signal.rule.entry)
(ns quanta.trade.entry-signal.entry.core)

(defmulti positionsize2
(fn [{:keys [type] :as opts}] type))
Expand All @@ -18,12 +18,11 @@
(and signal ; signal might be nil
(contains? #{:long :short} signal)))

(defn create-position [{:keys [asset entrysize-fn]}
{:keys [row] :as data}]
(let [{:keys [date idx close entry] } row]
{:side entry
(defn create-position [{:keys [asset entrysize-fn]}
{:keys [date idx close entry] :as row}]
{:side entry
:asset asset
:qty (entrysize-fn close)
:entry-idx idx
:entry-date date
:entry-price close}))
:entry-price close})
49 changes: 49 additions & 0 deletions src/quanta/trade/entry_signal/exit/config.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
(ns quanta.trade.entry-signal.exit.config
(:require
[quanta.trade.entry-signal.exit.position :as e])
(:import
[quanta.trade.entry_signal.exit.position TakeProfit TrailingStopLoss MultipleRules]))

(defmulti exit-rule
(fn [{:keys [type] :as opts}]
type))

(defmethod exit-rule :profit-prct [{:keys [label prct]
:or {label :profit-prct}}]
(assert prct "take-profit-prct needs :prct parameter")
(fn [{:keys [entry-price side] :as position}]
;(println "creating profit-prct rule for position: " position)
(assert entry-price "take-profit-prct needs :position :entry-price")
(assert side "take-profit-prct needs :position :side")
(let [prct (/ prct 100.0)
level (case side
:long (* entry-price (+ 1.0 prct))
:short (/ entry-price (+ 1.0 prct)))]
(TakeProfit. position level label))))

(defmethod exit-rule :trailing-stop-offset [{:keys [col label]
:or {label :trailing-stop}}]
(assert col "trailing-stop-offset needs :col parameter")
(fn [position]
;(assert entry-price "trailing-stop-offset needs :position :entry-price")
;(assert side "trailing-stop-offset needs :position :side")
(let [;_ (assert offset (str "trailing-stop-offset needs :row " col " value"))
level-initial nil
level-a (atom level-initial)
new-level-fn (fn [position level row]
(let [{:keys [entry-price side]} position
offset (get row col)
close (:close row)
offset (get row col)]
(if level
(case side
:long (- close offset)
:short (+ close offset))
(case side
:long (- entry-price offset)
:short (+ entry-price offset)))))]
(TrailingStopLoss. position level-a new-level-fn label))))




Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns quanta.trade.entry-signal.rule.exit2)
(ns quanta.trade.entry-signal.exit.position)

(defprotocol IExit
(priority [_])
Expand Down Expand Up @@ -90,14 +90,24 @@
new-level (new-level-fn position @level-a row)
new-level (case (:side position)
:short
(when (< new-level @level-a)
(when (or (nil? @level-a)
(< new-level @level-a))
new-level)
:long
(when (> new-level @level-a)
(when (or (nil? @level-a)
(> new-level @level-a))
new-level))]
(when new-level
(println "TrailingStopLoss changes from " @level-a " to: " new-level)
(reset! level-a new-level))
r)))


(defrecord MultipleRules [rules]
IExit
(check-exit [_ {:keys [high low] :as row}]
(->> rules
(map #(check-exit % row))
(remove nil?)
first)))

Loading

0 comments on commit 8b65d8c

Please sign in to comment.