χρόνος

Chronos Code: NYSE Trading Holidays

For more information: The Chronos Date/Time Library 


Here we present the Chronos code that generates the list of each day the New York Stock Exchange was closed the entire day from 1885 through the current year. The list does not show any Sundays, nor any Saturdays from 1953 onwards. The NYSE had a two hour trading session (10am to Noon) on Saturdays from 1873 through 1952.  To see the list: NYSE Full-Day Closures, 1885-Present.

The code depends upon the fact that the 'SemanticDatePolicy nyse' object knows both all the dates when the NYSE was closed for exceptional reasons (e.g., in observance of the First Lunar Landing by Apollo 11,) and also knows the current and former NYSE observance rules for 'regularly-scheduled' market holidays, such as Columbus day (until 1954) and New Year's Day (which is not observed when it falls on a Saturday.) Note that the  'SemanticDatePolicy nyse' object is just an instance of SemanticDatePolicy itself--it is not a specialized subclass coded to handle the NYSE rules and exceptions--nor is there any other such NYSE-specific class in the Chronos codebase.

| byYears intraYearList stream |
byYears := SortedCollection sortBlock: [:a :b | a key > b key].
1885 to: 2006 do: [:year |
    intraYearList := SortedCollection sortBlock: [:a :b | a key < b key].
    byYears add: year->intraYearList.
    SemanticDatePolicy nyse observedEventOccurenceDatesInYear: year do:
        [:semanticKey :date :observanceType |
        semanticKey == #weekend
            ifFalse:
                [intraYearList add:
                    date->(Array
                            with: semanticKey
"The semantic significance of the date."
                           with: observanceType)]]].
stream := 'NYSE_Observed_Holidays-1885-2006.txt' asFilename writeStream.
[byYears do: [:yearAssocToClosureList |
    | observanceType |
    yearAssocToClosureList value
        do: [:assoc |
            stream
                cr;
                nextPutAll: (assoc key printStringUsing: #rfc2822); "The date"
                nextPut: $:;
                tab;
                nextPutAll: assoc value first. "The semantic 
significance of the date."
            observanceType := assoc value last.
            observanceType == #nominal
                ifFalse:
                    ["The date was observed on some day other than the 'nominal' day."
                    stream
                        space;
                        nextPut: $(;
                        nextPutAll: observanceType;
                        nextPut: $)]].

stream cr]] ensure: [stream close].

One can also use the '
SemanticDatePolicy nyse' object to count the number of trading days between two dates, thusly:

[:minDate :maxDate |
| closureCount |
minDate > maxDate ifTrue: [^0].
closureCount := 0.
SemanticDatePolicy nyse
    observedEventOccurenceDatesFrom: minDate
    through: maxDate
    do: [:semanticKey :date :observanceType |
        semanticKey == #weekend
            ifTrue:
                [(date year between: 1873 and: 1952)
                    ifTrue: [date dayOfWeek = Sunday ifTrue: [closureCount := closureCount + 1]]
                    ifFalse: [closureCount := closureCount + 1]]
            ifFalse: [closureCount := closureCount + 1]].
"Must add 1 because it's a closed interval."
(minDate daysUntil: maxDate) + 1 - closureCount]
    value:
(YearMonthDay year: 2003 month: March day: 12)  
    value: (YearMonthDay year: 2006 month: January day: 12)