From f152bac804e542ce0989983e8c6419c50791eb24 Mon Sep 17 00:00:00 2001 From: wizard50 Date: Mon, 14 Oct 2024 14:37:49 -0300 Subject: [PATCH] added calendar open interval functions ta.calendar.core -> quanta.calendar.core --- lib/calendar/dev/src/dev/calendar_seq.clj | 17 +- lib/calendar/dev/src/dev/core.clj | 23 ++- .../quanta/notebook/calendar_window.clj | 30 +-- .../src/quanta/calendar/calendar_info.clj | 10 +- lib/calendar/src/quanta/calendar/core.clj | 189 +++++++++++++++++- lib/calendar/src/ta/calendar/core.clj | 157 +++------------ lib/calendar/test/ta/calendar/core_test.clj | 14 +- lib/calendar/test/ta/calendar/day_test.clj | 38 +++- 8 files changed, 305 insertions(+), 173 deletions(-) diff --git a/lib/calendar/dev/src/dev/calendar_seq.clj b/lib/calendar/dev/src/dev/calendar_seq.clj index f559d064..a3798a65 100644 --- a/lib/calendar/dev/src/dev/calendar_seq.clj +++ b/lib/calendar/dev/src/dev/calendar_seq.clj @@ -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]" @@ -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]" @@ -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]" @@ -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]" @@ -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]" @@ -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)) \ No newline at end of file diff --git a/lib/calendar/dev/src/dev/core.clj b/lib/calendar/dev/src/dev/core.clj index f5a86e47..bde18819 100644 --- a/lib/calendar/dev/src/dev/core.clj +++ b/lib/calendar/dev/src/dev/core.clj @@ -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]" @@ -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) diff --git a/lib/calendar/resources/quanta/notebook/calendar_window.clj b/lib/calendar/resources/quanta/notebook/calendar_window.clj index 46b390aa..a9d146a7 100644 --- a/lib/calendar/resources/quanta/notebook/calendar_window.clj +++ b/lib/calendar/resources/quanta/notebook/calendar_window.clj @@ -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) @@ -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) diff --git a/lib/calendar/src/quanta/calendar/calendar_info.clj b/lib/calendar/src/quanta/calendar/calendar_info.clj index 4a20f114..b21b7dc7 100644 --- a/lib/calendar/src/quanta/calendar/calendar_info.clj +++ b/lib/calendar/src/quanta/calendar/calendar_info.clj @@ -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])) @@ -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)) ; ) diff --git a/lib/calendar/src/quanta/calendar/core.clj b/lib/calendar/src/quanta/calendar/core.clj index e948721b..511300d6 100644 --- a/lib/calendar/src/quanta/calendar/core.clj +++ b/lib/calendar/src/quanta/calendar/core.clj @@ -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] @@ -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. \ No newline at end of file +;; 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]))) \ No newline at end of file diff --git a/lib/calendar/src/ta/calendar/core.clj b/lib/calendar/src/ta/calendar/core.clj index d79f5598..a7f261af 100644 --- a/lib/calendar/src/ta/calendar/core.clj +++ b/lib/calendar/src/ta/calendar/core.clj @@ -1,174 +1,65 @@ (ns ta.calendar.core (:require [tick.core :as t] + [quanta.calendar.core :as cal] [ta.calendar.interval :refer [intervals get-calendar-day-duration get-calendar-month-duration] :as interval] - [ta.calendar.calendars :refer [calendars]] - [ta.calendar.core :as cal])) + [ta.calendar.calendars :refer [calendars]])) + +; TODO: +; this namespace is a wrapper and should be only used for legacy support +; use quanta.calendar.core instead (defn now-calendar [calendar-kw] - (let [calendar (calendar-kw calendars)] - (interval/now-calendar calendar))) + (cal/now-calendar calendar-kw)) (defn next-close - "dt needs to be calendar-time, - use current-close to align clock-time to calendar-time" [calendar-kw interval-kw dt] - (let [calendar (calendar-kw calendars) - interval (interval-kw intervals) - ;_ (println "calendar: " calendar) - ;_ (println "interval: " interval) - next-close-dt (:next-close interval)] - (next-close-dt calendar dt))) + (cal/next-close [calendar-kw interval-kw] dt)) (defn prior-close - "dt needs to be calendar-time, - use current-close to align clock-time to calendar-time" [calendar-kw interval-kw dt] - (let [calendar (calendar-kw calendars) - interval (interval-kw intervals) - _ (assert calendar) - _ (assert interval) - ;_ (println "calendar: " calendar) - ;_ (println "interval: " interval) - prior-close-dt (:prior-close interval)] - (prior-close-dt calendar dt))) + (cal/prior-close [calendar-kw interval-kw] dt)) (defn current-close - "use this function to align clock-time to calendar-time once" [calendar-kw interval-kw & [dt]] - (let [calendar (calendar-kw calendars) - interval (interval-kw intervals) - ;_ (println "calendar: " calendar) - ;_ (println "interval: " interval) - _ (assert calendar) - _ (assert interval) - current-close-dt (:current-close interval)] - (if dt - (current-close-dt calendar dt) - (current-close-dt calendar (t/now))))) + (cal/current-close [calendar-kw interval-kw] dt)) (defn current-close2 [[calendar-kw interval-kw] dt] - ; 2 reasons for this variation: - ; 1. calendar argument vector (not two args) this is our new syntax - ; 2. no optional arg, so in compression nothign goes wrong. - ; current-close should be replaced by this version. - (let [calendar (calendar-kw calendars) - interval (interval-kw intervals) - _ (assert calendar) - _ (assert interval) - current-close-dt (:current-close interval) - _ (assert dt "current close dt is nil.")] - (current-close-dt calendar dt))) - -(defn prior-open - "dt needs to be calendar-time, - use current-open to align clock-time to calendar-time" - [[calendar-kw interval-kw] dt] - (let [calendar (calendar-kw calendars) - interval (interval-kw intervals) - _ (assert calendar) - _ (assert interval) - ;_ (println "calendar: " calendar) - ;_ (println "interval: " interval) - prior-open-dt (:prior-open interval)] - (prior-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 + (cal/current-close [calendar-kw interval-kw] dt)) -(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 ; todo: [cal interval] instead of 2 parameter +(defn calendar-seq ([calendar-kw interval-kw] - (let [cur-dt (current-close calendar-kw interval-kw)] - (calendar-seq calendar-kw interval-kw cur-dt))) + (cal/calendar-seq [calendar-kw interval-kw])) ([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)))) + (cal/calendar-seq [calendar-kw interval-kw] dt))) (defn calendar-seq-instant [[calendar-kw interval-kw]] - (->> (calendar-seq calendar-kw interval-kw) - (map t/instant))) + (cal/calendar-seq-instant [calendar-kw interval-kw])) (defn calendar-seq-prior [[calendar-kw interval-kw] dt] - (let [cur-dt (current-close2 [calendar-kw interval-kw] dt) - prior-fn (partial prior-close calendar-kw interval-kw)] - (iterate prior-fn cur-dt))) + (cal/calendar-seq-prior [calendar-kw interval-kw] 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)))) + (cal/trailing-window calendar n end-dt)) ([calendar n] - (let [[calendar-kw interval-kw] calendar - cur-dt (current-close calendar-kw interval-kw)] - (take n (calendar-seq-prior [calendar-kw interval-kw] cur-dt))))) + (cal/trailing-window calendar n))) (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)})) + (cal/trailing-range calendar n end-dt)) ([calendar n] - (let [window (trailing-window calendar n)] - {:end (first window) - :start (last window)}))) + (cal/trailing-range calendar n))) (defn fixed-window - [[calendar-kw interval-kw] {:keys [start end]}] - (let [seq (calendar-seq-prior [calendar-kw interval-kw] end) - after-start? (fn [dt] (t/>= dt start))] - (take-while after-start? seq))) + [[calendar-kw interval-kw] window] + (cal/fixed-window [calendar-kw interval-kw] window)) (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}) + (cal/calendar-seq->range cal-seq)) (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]))) + (cal/get-bar-duration [calendar-kw interval-kw])) diff --git a/lib/calendar/test/ta/calendar/core_test.clj b/lib/calendar/test/ta/calendar/core_test.clj index c4060a93..62a2106f 100644 --- a/lib/calendar/test/ta/calendar/core_test.clj +++ b/lib/calendar/test/ta/calendar/core_test.clj @@ -3,7 +3,7 @@ [tick.core :as t] [ta.calendar.data.dates :refer :all] [ta.calendar.calendars :as cal] - [ta.calendar.core :refer [trailing-window calendar-seq fixed-window + [quanta.calendar.core :refer [trailing-window calendar-seq fixed-window close->open-dt open->close-dt]])) (defn print-seq [s] (for [i (range 0 (count s))] @@ -133,7 +133,7 @@ (deftest calendar-seq-forwards-d (testing "1 day seq - us" - (let [seq-5-us-d (take 5 (calendar-seq :us :d dt-monday-17-00))] + (let [seq-5-us-d (take 5 (calendar-seq [:us :d] dt-monday-17-00))] (is (= (nth seq-5-us-d 0) dt-monday-17-00)) (is (= (nth seq-5-us-d 1) dt-tuesday-17-00)) (is (= (nth seq-5-us-d 2) dt-wednesday-17-00)) @@ -141,7 +141,7 @@ (is (= (nth seq-5-us-d 4) dt-friday-17-00)) (is (not (= (nth seq-5-us-d 0) dt-prev-friday-17-00))))) (testing "1 day seq - us over a week" - (let [seq-5-us-d (take 5 (calendar-seq :us :d dt-prev-friday-17-00))] + (let [seq-5-us-d (take 5 (calendar-seq [:us :d] dt-prev-friday-17-00))] (is (= (nth seq-5-us-d 0) dt-prev-friday-17-00)) (is (= (nth seq-5-us-d 1) dt-monday-17-00)) (is (= (nth seq-5-us-d 2) dt-tuesday-17-00)) @@ -149,7 +149,7 @@ (is (= (nth seq-5-us-d 4) dt-thursday-17-00)) (is (not (= (nth seq-5-us-d 0) dt-friday-17-00))))) (testing "1 day seq - us over a week - inside interval" - (let [seq-5-us-d (take 7 (calendar-seq :us :d dt-prev-friday-17-00-30))] + (let [seq-5-us-d (take 7 (calendar-seq [:us :d] dt-prev-friday-17-00-30))] (is (= (nth seq-5-us-d 0) dt-prev-friday-17-00)) (is (= (nth seq-5-us-d 1) dt-monday-17-00)) (is (= (nth seq-5-us-d 2) dt-tuesday-17-00)) @@ -159,7 +159,7 @@ (is (= (nth seq-5-us-d 6) dt-monday-next-17-00)) (is (not (= (nth seq-5-us-d 0) dt-friday-17-00))))) (testing "1 day seq - forex over a week - inside interval" - (let [seq-5-us-d (take 7 (calendar-seq :forex :d dt-prev-friday-16-30))] + (let [seq-5-us-d (take 7 (calendar-seq [:forex :d] dt-prev-friday-16-30))] (is (= (nth seq-5-us-d 0) dt-prev-friday-16-30)) (is (= (nth seq-5-us-d 1) dt-monday-16-30)) (is (= (nth seq-5-us-d 2) dt-tuesday-16-30)) @@ -171,7 +171,7 @@ (deftest calendar-seq-forwards-m (testing "1 min seq - us" - (let [seq-5-us-d (take 5 (calendar-seq :us :m dt-thursday-12-55))] + (let [seq-5-us-d (take 5 (calendar-seq [:us :m] dt-thursday-12-55))] (is (= (nth seq-5-us-d 0) dt-thursday-12-55)) (is (= (nth seq-5-us-d 1) dt-thursday-12-56)) (is (= (nth seq-5-us-d 2) dt-thursday-12-57)) @@ -188,7 +188,7 @@ ; (is (= (nth seq-5-us-d 4) dt-thursday-17-00)) ; (is (not (= (nth seq-5-us-d 0) dt-friday-17-00))))) (testing "1 min seq - forex - jump into next trading day" - (let [seq-5-us-d (take 5 (calendar-seq :forex :m dt-thursday-16-27))] + (let [seq-5-us-d (take 5 (calendar-seq [:forex :m] dt-thursday-16-27))] (is (= (nth seq-5-us-d 0) dt-thursday-16-27)) (is (= (nth seq-5-us-d 1) dt-thursday-16-28)) (is (= (nth seq-5-us-d 2) dt-thursday-16-29)) diff --git a/lib/calendar/test/ta/calendar/day_test.clj b/lib/calendar/test/ta/calendar/day_test.clj index 01d58d77..56f788ae 100644 --- a/lib/calendar/test/ta/calendar/day_test.clj +++ b/lib/calendar/test/ta/calendar/day_test.clj @@ -2,7 +2,8 @@ (:require [clojure.test :refer :all] [tick.core :as t] - [ta.calendar.core :refer [trailing-window calendar-seq fixed-window + [quanta.calendar.core :refer [next-close + trailing-window calendar-seq fixed-window close->open-dt open->close-dt]] [ta.calendar.data.dates :refer :all] [ta.calendar.calendars :as cal] @@ -330,6 +331,41 @@ (is (t/= dt-thursday-16-30 (prior-close-dt forex-cal dt-thursday-16-45))) (is (not (t/= dt-friday-17-00 (prior-close-dt forex-cal dt-thursday-16-45))))))) +;; EU +(deftest next-close-daily-eu + (let [eu-cal (:eu cal/calendars) + sun-00-27 (t/in (t/date-time "2024-10-13T00:27") (:timezone eu-cal)) + fri-17-00 (t/in (t/date-time "2024-10-11T17:00") (:timezone eu-cal)) + mon-17-00 (t/in (t/date-time "2024-10-14T17:00") (:timezone eu-cal))] + (testing "dt inside interval" + (is (t/= mon-17-00 (next-close [:eu :d] sun-00-27))) + (is (not (t/= fri-17-00 (next-close [:eu :d] sun-00-27))))) + ;(testing "dt on interval boundary" + ; (is (t/= dt-friday-17-00 (next-close-dt eu-cal dt-thursday-17-00))) + ; (is (not (t/= dt-thursday-17-00 (next-close-dt eu-cal dt-thursday-17-00))))) + ;(testing "dt before trading hours" + ; (is (t/= dt-friday-17-00 (next-close-dt eu-cal dt-friday-06-00))) + ; (is (not (t/= dt-thursday-17-00 (next-close-dt eu-cal dt-friday-06-00))))) + ;(testing "dt after trading hours" + ; (is (t/= dt-friday-17-00 (next-close-dt eu-cal dt-thursday-23-00))) + ; (is (not (t/= dt-thursday-17-00 (next-close-dt eu-cal dt-thursday-23-00))))) + ;(testing "dt before trading hours (from next week)" + ; (is (t/= dt-monday-next-17-00 (next-close-dt eu-cal dt-monday-next-06-00))) + ; (is (not (t/= dt-friday-17-00 (next-close-dt eu-cal dt-monday-next-06-00))))) + ;(testing "dt after trading hours (weekend)" + ; (is (t/= dt-monday-next-17-00 (next-close-dt eu-cal dt-friday-18-00))) + ; (is (not (t/= dt-friday-17-00 (next-close-dt eu-cal dt-friday-18-00))))) + ;(testing "dt on trading week start" + ; (is (t/= dt-monday-next-17-00 (next-close-dt eu-cal dt-monday-next-09-00))) + ; (is (not (t/= dt-friday-17-00 (next-close-dt eu-cal dt-monday-next-09-00))))) + ;(testing "dt on trading week close" + ; (is (t/= dt-monday-next-17-00 (next-close-dt eu-cal dt-friday-17-00))) + ; (is (not (t/= dt-friday-17-00 (next-close-dt eu-cal dt-friday-17-00))))) + ;(testing "dt not on trading day" + ; (is (t/= dt-monday-next-17-00 (next-close-dt eu-cal dt-saturday-12-00))) + ; (is (not (t/= dt-saturday-17-00 (next-close-dt eu-cal dt-saturday-12-00))))) + )) + ;; crypto daily seq test