-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
4,990 additions
and
2,080 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,14 @@ | ||
repos: | ||
- repo: https://github.com/astral-sh/ruff-pre-commit | ||
# Ruff version. | ||
rev: v0.0.275 | ||
rev: v0.3.2 | ||
hooks: | ||
# Run the linter. | ||
- id: ruff | ||
# Run the formatter. | ||
- id: ruff-format | ||
- repo: https://github.com/asottile/pyupgrade | ||
rev: v3.15.2 | ||
hooks: | ||
- id: pyupgrade | ||
args: ["--py39-plus"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
--- | ||
title: "Metadata" | ||
draft: false | ||
type: docs | ||
layout: "single" | ||
|
||
menu: | ||
docs_extensions: | ||
weight: 60 | ||
--- | ||
# Metadata | ||
|
||
Metadata in the form of tags and comments can be associated with specific dates. Metadata can be a combination of a | ||
single string comment and/or a set of string tags. For example, | ||
```python | ||
import pandas as pd | ||
|
||
import exchange_calendars_extensions.core as ecx | ||
ecx.apply_extensions() | ||
import exchange_calendars as ec | ||
|
||
# Add metadata. | ||
ecx.set_comment('XLON', '2022-01-01', "This is a comment.") | ||
ecx.set_tags('XLON', '2022-01-01', {'tag1', 'tag2'}) | ||
|
||
calendar = ec.get_calendar('XLON') | ||
|
||
# Get metadata. | ||
meta_dict = calendar.meta() | ||
print(len(meta_dict)) | ||
|
||
# The value for the first and only date. | ||
meta = meta_dict[pd.Timestamp('2022-01-01')] | ||
|
||
print(meta.comment) | ||
print(meta.tags) | ||
``` | ||
will print | ||
```text | ||
1 | ||
This is a comment. | ||
{'tag1', 'tag2'} | ||
``` | ||
|
||
The `meta()` method returns an ordered dictionary of type `Dict[pd.Timestamp, DayMeta]` that contains all days that have | ||
metadata associated with them, ordered by date. The keys are `DateLike` timezone-naive Pandas timestamps normalized to | ||
midnight. Each timestamp represents a full day starting at midnight (inclusive) and ending at midnight (exclusive) of | ||
the following day within the relevant timezone for the exchange. | ||
|
||
|
||
{{% note %}} | ||
Currently, the dictionary returned by the `meta()` method does not support lookup from values other than | ||
`pandas.Timestamp`. This means that it is not possible to look up metadata for a specific date using a string. | ||
{{% /note %}} | ||
|
||
Dates can be filtered by a start and an end timestamp. For example, | ||
```python | ||
import pandas as pd | ||
|
||
import exchange_calendars_extensions.core as ecx | ||
ecx.apply_extensions() | ||
import exchange_calendars as ec | ||
|
||
# Add metadata for two dates. | ||
ecx.set_comment('XLON', '2022-01-01', "This is a comment.") | ||
ecx.set_tags('XLON', '2022-01-01', {'tag1', 'tag2'}) | ||
ecx.set_comment('XLON', '2022-01-02', "This is another comment.") | ||
ecx.set_tags('XLON', '2022-01-02', {'tag3', 'tag4'}) | ||
|
||
calendar = ec.get_calendar('XLON') | ||
|
||
# Get metadata only for 2022-01-01. | ||
meta_dict = calendar.meta(start='2022-01-01', end='2022-01-01') | ||
print(len(meta_dict)) | ||
|
||
# The value for the first and only date. | ||
meta = meta_dict[pd.Timestamp('2022-01-01')] | ||
|
||
print(meta.comment) | ||
print(meta.tags) | ||
``` | ||
will print | ||
```text | ||
1 | ||
This is a comment. | ||
{'tag1', 'tag2'} | ||
``` | ||
|
||
The `meta()` method supports `TimestampLike` `start` and `end` arguments which must be either both timezone-naive or | ||
timezone-aware. Otherwise, a `ValueError` is raised. | ||
|
||
The returned dictionary includes all days with metadata that have a non-empty intersection with the period between | ||
the `start` and `end`. This result is probably what one would usually expect, even in situations where `start` and/or | ||
`end` are not aligned to midnight. In the above example, if `start` were `2022-01-01 06:00:00` and `end` were | ||
`2022-01-01 18:00:00`, the result would be the same since the intersection with the full day `2022-01-01` is non-empty. | ||
|
||
When `start` and `end` are timezone-naive, as in the examples above, the timezone of the exchange does not matter. Like | ||
`start` and `end`, the timestamps that mark the beginning and end of a day are used timezone-naive. Effectively, any | ||
comparison uses timestamps with a wall-clock time component. | ||
|
||
In contrast, when `start` and `end` timestamps are timezone-aware, all other timestamps also used timezone-aware and | ||
with the exchange's native timezone. Comparisons are then done between instants, i.e. actual points on the timeline. | ||
|
||
The difference between the two cases is illustrated in the following example which considers the date 2024-03-31. In | ||
timezones that are based on Central European Time (CET), a transition to Central European Summer Time (CEST) occurs on | ||
this date. The transition happens at 02:00:00 CET, which is 03:00:00 CEST, i.e. clocks advance by one hour and the day | ||
is 23 hours long. | ||
```python | ||
import pandas as pd | ||
|
||
import exchange_calendars_extensions.core as ecx | ||
from collections import OrderedDict | ||
from exchange_calendars_extensions.api.changes import DayMeta | ||
ecx.apply_extensions() | ||
import exchange_calendars as ec | ||
|
||
# Add metadata. | ||
day = pd.Timestamp("2024-03-31") | ||
meta = DayMeta(tags=[], comment="This is a comment") | ||
ecx.set_meta('XETR', day, meta) | ||
|
||
calendar = ec.get_calendar('XETR') | ||
|
||
# Get metadata for 2024-03-31, timezone-naive. | ||
assert calendar.meta(start='2024-03-31 00:00:00') == OrderedDict([(day, meta)]) | ||
assert calendar.meta(start='2024-03-31 23:59:59') == OrderedDict([(day, meta)]) | ||
|
||
# Get metadata for 2024-03-31, timezone-aware. | ||
# 2024-03-30 23:00:00 UTC is 2024-03-31 00:00:00 CET. | ||
assert calendar.meta(start=pd.Timestamp('2024-03-30 23:00:00').tz_localize("UTC")) == OrderedDict([(day, meta)]) | ||
# 2024-03-31 21:59:59 UTC is 2024-03-31 23:59:59 CEST. | ||
assert calendar.meta(start=pd.Timestamp('2024-03-31 21:59:59').tz_localize("UTC")) == OrderedDict([(day, meta)]) | ||
# 2024-03-31 22:00:00 UTC is 2024-03-31 00:00:00 CEST. | ||
assert calendar.meta(start=pd.Timestamp('2024-03-31 22:00:00').tz_localize("UTC")) == OrderedDict([]) | ||
``` |
Oops, something went wrong.