Skip to content

Commit

Permalink
added calendar open interval functions
Browse files Browse the repository at this point in the history
ta.calendar.core -> quanta.calendar.core
  • Loading branch information
wizard50 committed Oct 14, 2024
1 parent 84003d8 commit f152bac
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 173 deletions.
17 changes: 11 additions & 6 deletions lib/calendar/dev/src/dev/calendar_seq.clj
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
(ns dev.calendar-seq
(:require
[tick.core :as t]
[ta.calendar.core :refer [trailing-window calendar-seq fixed-window
[quanta.calendar.core :refer [trailing-window calendar-seq calendar-seq-prior
fixed-window
close->open-dt open->close-dt]]
[ta.calendar.calendars :refer [calendars]]
[dev.utils :refer [to-utc]]))


(->> (t/in (t/date-time "2024-10-01T16:20:00") "America/New_York")
(calendar-seq :forex :d)
(calendar-seq [:forex :d])
(take 15))
;=>
;(#time/zoned-date-time"2024-09-30T16:30-04:00[America/New_York]"
Expand All @@ -28,7 +29,7 @@
; #time/zoned-date-time"2024-10-18T16:30-04:00[America/New_York]")

(->> (t/in (t/date-time "2024-10-01T17:32:00") "America/New_York")
(calendar-seq :forex :h)
(calendar-seq [:forex :h])
(take 15))
;=>
;(#time/zoned-date-time"2024-10-01T16:30-04:00[America/New_York]"
Expand All @@ -48,7 +49,7 @@
; #time/zoned-date-time"2024-10-02T07:00-04:00[America/New_York]")

(->> (t/in (t/date-time "2024-10-01T17:32:00") "America/New_York")
(calendar-seq :forex :m)
(calendar-seq [:forex :m])
(take 15))
;=>
;(#time/zoned-date-time"2024-10-01T17:32-04:00[America/New_York]"
Expand All @@ -68,7 +69,7 @@
; #time/zoned-date-time"2024-10-01T17:46-04:00[America/New_York]")

(->> (t/in (t/date-time "2024-02-09T00:00:00") "America/New_York")
(calendar-seq :forex :h4)
(calendar-seq [:forex :h4])
(take 15))
;=>
;(#time/zoned-date-time"2024-02-08T21:00-05:00[America/New_York]"
Expand All @@ -88,7 +89,7 @@
; #time/zoned-date-time"2024-02-13T13:00-05:00[America/New_York]")

(->> (t/in (t/date-time "2024-02-11T06:00:00") "America/New_York")
(calendar-seq :forex :m15)
(calendar-seq [:forex :m15])
(take 15))
;=>
;(#time/zoned-date-time"2024-02-09T16:30-05:00[America/New_York]"
Expand All @@ -106,3 +107,7 @@
; #time/zoned-date-time"2024-02-11T20:00-05:00[America/New_York]"
; #time/zoned-date-time"2024-02-11T20:15-05:00[America/New_York]"
; #time/zoned-date-time"2024-02-11T20:30-05:00[America/New_York]")

(->> (t/in (t/date-time "2024-10-01T23:59:59.999999999") "UTC")
(calendar-seq-prior [:crypto :d])
(take 20))
23 changes: 19 additions & 4 deletions lib/calendar/dev/src/dev/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
[tick.core :as t]
[ta.calendar.calendars :refer [calendars]]
[ta.calendar.interval :refer [intervals]]
[ta.calendar.core :refer [close->open-dt open->close-dt current-close2]]
[quanta.calendar.core :refer [next-close current-close close->open-dt open->close-dt current-close2]]
[dev.utils :refer [to-utc]]))

(current-close2 [:crypto :m]
(current-close [:crypto :m]
(t/in (t/date-time "2024-02-08T23:59:30") "UTC"))
;=> #time/zoned-date-time"2024-02-08T23:59Z[UTC]"

(current-close2 [:crypto :m]
(current-close [:crypto :m]
(t/in (t/date-time "2024-02-08T23:59:59") "UTC"))
;=> #time/zoned-date-time"2024-02-08T23:59Z[UTC]"

(current-close2 [:crypto :m]
(current-close [:crypto :m]
(t/in (t/date-time "2024-02-09T00:00:00") "UTC"))
;=> #time/zoned-date-time"2024-02-08T23:59:59.999999999Z[UTC]"

Expand Down Expand Up @@ -63,3 +63,18 @@
next-close-dt (:next-close interval)]
(next-close-dt calendar (t/in (t/date-time "2024-02-06T15:30") "America/New_York")))
;=> #time/zoned-date-time"2024-02-06T17:00-05:00[America/New_York]"


(let [eu-cal (:eu calendars)
sun-00-27 (t/in (t/date-time "2024-10-13T00:27") (:timezone eu-cal))
cur-close-dt (current-close [:eu :d] sun-00-27)
cur-close-instant (t/instant cur-close-dt)
next-close-dt (next-close [:eu :d] cur-close-dt)
next-close-instant (next-close [:eu :d] cur-close-instant)]
{:sun-00-27 sun-00-27
:cur-close-dt cur-close-dt
:cur-close-instant cur-close-instant
:next-close-dt next-close-dt
:next-close-instant next-close-instant})

(t/instant)
30 changes: 15 additions & 15 deletions lib/calendar/resources/quanta/notebook/calendar_window.clj
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
(ns quanta.notebook.calendar-window
(:require
[tick.core :as t]
[ta.calendar.core :as cal]))
[quanta.calendar.core :as cal]))



(cal/now-calendar :us)
(cal/now-calendar :eu)

(cal/next-close :us :d (cal/now-calendar :us))
(cal/next-close :us :h (cal/now-calendar :us))
(cal/next-close [:us :d] (cal/now-calendar :us))
(cal/next-close [:us :h] (cal/now-calendar :us))

(cal/prior-close :us :d (cal/now-calendar :us))
(cal/prior-close :us :h (cal/now-calendar :us))
(cal/prior-close [:us :d] (cal/now-calendar :us))
(cal/prior-close [:us :h] (cal/now-calendar :us))

(cal/current-close :us :d)
(cal/current-close :us :h)
(cal/current-close :us :m)
(cal/current-close [:us :d] (cal/now-calendar :us))
(cal/current-close [:us :h] (cal/now-calendar :us))
(cal/current-close [:us :m] (cal/now-calendar :us))

(take 5 (cal/calendar-seq :us :d))
(take 5 (cal/calendar-seq [:us :d]))
(take 5 (cal/calendar-seq-instant [:us :d]))

(take 5 (cal/calendar-seq :eu :d))
(take 5 (cal/calendar-seq :forex :m))
(take 5 (cal/calendar-seq [:eu :d]))
(take 5 (cal/calendar-seq [:forex :m]))

(take 30 (cal/calendar-seq :us :d))
(take 100 (cal/calendar-seq :eu :h))
(take 30 (cal/calendar-seq [:us :d]))
(take 100 (cal/calendar-seq [:eu :h]))
(take 100 (cal/calendar-seq-prior [:eu :h] (t/date-time "2023-01-01T00:00:00")))

(take 5 (cal/calendar-seq :eu :h))
(take 5 (cal/calendar-seq [:eu :h]))

(cal/trailing-window [:us :d] 5)
(cal/trailing-window [:us :d] 10)
Expand All @@ -41,7 +41,7 @@
:end (t/date-time "2023-02-01T00:00:00")})
cal/calendar-seq->range)

(-> (cal/trailing-window :us :d 5)
(-> (cal/trailing-window [:us :d] 5)
cal/calendar-seq->range)

(cal/trailing-range [:us :d] 2)
Expand Down
10 changes: 5 additions & 5 deletions lib/calendar/src/quanta/calendar/calendar_info.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns quanta.calendar.calendar-info
(:require
[tick.core :as t]
[ta.calendar.core :as cal]
[quanta.calendar.core :as cal]
[ta.calendar.calendars :as caldb]
[ta.calendar.helper :as calhelp]))

Expand All @@ -18,19 +18,19 @@
:business business?
:calendar-time (t/date-time dt-cal)}))

(defn gather-calendar [calendar-kw interval-kw dt]
(let [current-close-dt (cal/current-close calendar-kw interval-kw dt)]
(defn gather-calendar [[calendar-kw interval-kw] dt]
(let [current-close-dt (cal/current-close [calendar-kw interval-kw] dt)]
(assoc (market-info calendar-kw)
:calendar [calendar-kw interval-kw]
;:prior (t/instant (cal/prior-close calendar-kw interval-kw dt))
:current (t/instant current-close-dt)
:next (t/instant (cal/next-close calendar-kw interval-kw current-close-dt)))))
:next (t/instant (cal/next-close [calendar-kw interval-kw] current-close-dt)))))

(comment
(market-info :crypto)
(market-info :eu)

(gather-calendar :crypto :m (t/instant))
(gather-calendar [:crypto :m] (t/instant))

;
)
189 changes: 187 additions & 2 deletions lib/calendar/src/quanta/calendar/core.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
(ns quanta.calendar.core)
(ns quanta.calendar.core
(:require
[tick.core :as t]
[ta.calendar.interval :refer [intervals
get-calendar-day-duration
get-calendar-month-duration] :as interval]
[ta.calendar.calendars :refer [calendars]]))

; to find a calendar we use one vector param: [:forex :d]

Expand All @@ -10,4 +16,183 @@
; and then in quanta.calendar.core we only use a loaded calendar.
; this avoids many error checkings, I guess.

;; all function should have docstrings and be tested.
;; all function should have docstrings and be tested.

(defn now-calendar [calendar-kw]
(let [calendar (calendar-kw calendars)]
(interval/now-calendar calendar)))

(defn next-close
"returns the next bar close time.
dt has to be in the calendar timezone.
if dt is an aligned bar close time, then the close time of the next bar will be returned."
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
next-close-dt (:next-close interval)]
(next-close-dt calendar dt)))

(defn prior-close
"returns the prior bar close time.
dt has to be in the calendar timezone.
if dt is an aligned bar close time, then the close time of the prior bar will be returned."
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
prior-close-dt (:prior-close interval)]
(prior-close-dt calendar dt)))

(defn current-close
"use this function to align dt to a bar close time.
returns the close time of the current bar (last bar when the market is closed).
dt has to be in the calendar timezone.
if dt is an aligned bar close time, then this close time will be returned."
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
_ (assert dt "current close dt is nil.")
current-close-dt (:current-close interval)]
(current-close-dt calendar dt)))

(defn next-open
"returns the next bar open time.
dt has to be in the calendar timezone.
if dt is an aligned bar open time, then the open time of the next bar will be returned."
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
next-open-dt (:next-open interval)]
(next-open-dt calendar dt)))

(defn prior-open
"returns the prior bar open time.
dt has to be in the calendar timezone.
if dt is an aligned bar open time, then the open time of the prior bar will be returned.
if dt is not an aligned bar open time, then the open time of the current bar will be returned"
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
prior-open-dt (:prior-open interval)]
(prior-open-dt calendar dt)))

(defn current-open
"use this function to align dt to a bar open time.
returns the open time of the current bar (last bar when the market is closed).
dt has to be in the calendar timezone.
if dt is an aligned bar open time, then this open time will be returned."
[[calendar-kw interval-kw] dt]
(let [calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
_ (assert dt "current open dt is nil.")
current-open-dt (:current-open interval)]
(current-open-dt calendar dt)))

(defn close->open-dt [[calendar-kw interval-kw] & [dt]]
(let [dt (if dt dt (t/now))
calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
_ (assert dt "current close dt is nil.")
current-close-dt (:current-close interval)
current-open-dt (:current-open interval)
prior-open-dt (:prior-open interval)
aligned-close-dt (current-close-dt calendar dt)]
(if (= aligned-close-dt dt)
(prior-open-dt calendar aligned-close-dt) ; dt is aligned close -> new candle started. prior open needed
(current-open-dt calendar aligned-close-dt)))) ; dt is not alined close -> unfinished candle. current open needed

(defn open->close-dt [[calendar-kw interval-kw] & [dt]]
(let [dt (if dt dt (t/now))
calendar (calendar-kw calendars)
interval (interval-kw intervals)
_ (assert calendar)
_ (assert interval)
_ (assert dt "current open dt is nil.")
current-open-dt (:current-open interval)
next-close-dt (:next-close interval)
aligned-open-dt (current-open-dt calendar dt)]
(next-close-dt calendar aligned-open-dt)))

(defn calendar-seq
([[calendar-kw interval-kw]]
(let [now (now-calendar calendar-kw)
cur-dt (current-close [calendar-kw interval-kw] now)]
(calendar-seq [calendar-kw interval-kw] cur-dt)))
([[calendar-kw interval-kw] dt]
(let [cur-dt (current-close [calendar-kw interval-kw] dt)
next-dt (partial next-close [calendar-kw interval-kw])]
(iterate next-dt cur-dt))))

(defn calendar-seq-instant [[calendar-kw interval-kw]]
(->> (calendar-seq [calendar-kw interval-kw])
(map t/instant)))

(defn calendar-seq-prior [[calendar-kw interval-kw] dt]
(let [cur-dt (current-close [calendar-kw interval-kw] dt)
prior-fn (partial prior-close [calendar-kw interval-kw])]
(iterate prior-fn cur-dt)))

(defn trailing-window
"returns a calendar-seq for a calendar of n rows
if end-dt specified then last date equals end-date,
otherwise end-dt is equal to the most-recent close of the calendar"
([calendar n end-dt]
(let [[calendar-kw interval-kw] calendar]
(take n (calendar-seq-prior [calendar-kw interval-kw] end-dt))))
([calendar n]
(let [[calendar-kw interval-kw] calendar
now (now-calendar calendar-kw)
cur-dt (current-close [calendar-kw interval-kw] now)]
(take n (calendar-seq-prior [calendar-kw interval-kw] cur-dt)))))

(defn trailing-range
"returns a calendar-range for a calendar of n rows
if end-dt specified then last date equals end-date,
otherwise end-dt is equal to the most-recent close of the calendar"
([calendar n end-dt]
(let [window (trailing-window calendar n end-dt)]
{:end (first window)
:start (last window)}))
([calendar n]
(let [window (trailing-window calendar n)]
{:end (first window)
:start (last window)})))

(defn fixed-window
[[calendar-kw interval-kw] {:keys [start end] :as window}]
(let [seq (calendar-seq-prior [calendar-kw interval-kw] end)
after-start? (fn [dt] (t/>= dt start))]
(take-while after-start? seq)))

(defn calendar-seq->range [cal-seq]
{:start (last cal-seq)
:end (first cal-seq)})

(defn get-bar-window [[calendar-kw interval-kw] bar-end-dt]
; TODO: improve
; for intraday bars this works fine
; for the first bar if the day this is incorrect.
{:start (prior-close [calendar-kw interval-kw] bar-end-dt)
:end bar-end-dt})

(defn get-bar-duration
"returns duration in seconds of the given calendar"
[[calendar-kw interval-kw]]
(case interval-kw
; TODO
;:Y
;:M (get-calendar-month-duration calendar-kw)
;:W
:d (get-calendar-day-duration calendar-kw)
(get-in intervals [interval-kw :duration])))
Loading

0 comments on commit f152bac

Please sign in to comment.