Files
MoFin/venv/lib/python3.12/site-packages/exchange_calendars/exchange_calendar_xsgo.py
T
知微 fa45d8aa5f fix: 小果地址统一node122(兼容LAN+EasyTier)
- health_checklist.json: 192.168.1.122→node122
- ocr_client.py: docstring IP→node122
- docs/market-data-requirements.md: IP→node122
- 所有API调用通过ProxyHandler({})绕过系统代理
  Privoxy对node122:18003返回500,直连正常
2026-06-30 02:56:35 +08:00

316 lines
8.3 KiB
Python

#
# Copyright 2019 Quantopian, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
from zoneinfo import ZoneInfo
import pandas as pd
from pandas.tseries.holiday import Easter, GoodFriday, Holiday
from pandas.tseries.offsets import Day
from .common_holidays import (
all_saints_day,
assumption_day,
christmas,
christmas_eve,
european_labour_day,
immaculate_conception,
maundy_thursday,
new_years_day,
new_years_eve,
saint_peter_and_saint_paul_day,
)
from .exchange_calendar import (
FRIDAY,
MONDAY,
THURSDAY,
TUESDAY,
WEDNESDAY,
WEEKDAYS,
HolidayCalendar,
ExchangeCalendar,
)
def summer_solstice(dt: datetime.datetime) -> datetime.datetime:
"""
The summer solstice is on June 20th, but in some years it can be on the
21st.
"""
day = 20
if (dt.year % 4 > 1 and dt.year <= 2046) or (dt.year % 4 > 2 and dt.year <= 2075):
day = 21
return dt.replace(month=6, day=day)
def national_day_of_indigenous_peoples_observed(
dt: datetime.datetime,
) -> datetime.datetime | None:
"""
Observed on the summer solstice, but in 2021 it was moved to June 21st.
"""
if dt.year == 2021:
dt = dt.replace(month=6, day=21)
elif dt.year > 2021:
dt = summer_solstice(dt)
else:
dt = None
return dt
def nearest_monday(dt: datetime.datetime) -> datetime.datetime:
"""
If the holiday falls on a Saturday, Sunday or Monday then the date is
unchanged (Sat/Sun observances are not made up), otherwise use the closest
Monday to the date.
"""
day = dt.weekday()
if day in (TUESDAY, WEDNESDAY, THURSDAY):
return dt - datetime.timedelta(day - MONDAY)
if day == FRIDAY:
return dt + datetime.timedelta(3)
return dt
def tuesday_and_wednesday_to_friday(dt: datetime.datetime) -> datetime.datetime:
"""
If Evangelical Church Day (Halloween) falls on a Tuesday, it is observed
the preceding Friday. If it falls on a Wednesday, it is observed the next
Friday. If it falls on Thu, Fri, Sat, Sun, or Mon the date is unchanged.
"""
day = dt.weekday()
if day == TUESDAY:
return dt - datetime.timedelta(4)
if day == WEDNESDAY:
return dt + datetime.timedelta(2)
return dt
def not_2010(dt: datetime.datetime) -> datetime.datetime | None:
"""
In 2010 Independence Day fell on a Saturday. Normally this would mean that
Friday is a half day, but instead it is a full day off, so we need to
exclude it from the usual half day rules.
"""
return None if dt.year == 2010 else dt
NewYearsDay = new_years_day()
MaundyThursday = maundy_thursday()
MondayPriorToCorpusChristi = Holiday(
"Monday Prior to Corpus Christi",
month=1,
day=1,
offset=[Easter(), Day(57)],
end_date="2008",
)
LabourDay = european_labour_day()
NavyDay = Holiday("Navy Day", month=5, day=21)
NationalDayOfIndigenousPeoples = Holiday(
"National Day of Indigenous Peoples",
month=6,
day=19,
observance=national_day_of_indigenous_peoples_observed,
start_date="2021",
)
SaintPeterAndSaintPaulDay = saint_peter_and_saint_paul_day(
observance=nearest_monday,
)
OurLadyOfMountCarmelDay = Holiday(
"Our Lady of Mount Carmel's Day",
month=7,
day=16,
start_date="2008",
)
AssumptionDay = assumption_day()
PublicHolidayMonday = Holiday(
"Public Holiday Preceeding a Tuesday Independence Day",
month=9,
day=17,
start_date="2003",
days_of_week=(MONDAY,),
)
DayBeforeIndependenceDay = Holiday(
"Day Before Independence Day",
month=9,
day=17,
observance=not_2010,
days_of_week=(TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
)
IndependenceDay = Holiday("Independence Day", month=9, day=18)
ArmyDay = Holiday("Army Day", month=9, day=19)
PublicHolidayFriday = Holiday(
"Public Holiday Following a Thursday Army Day",
month=9,
day=20,
start_date="2003",
days_of_week=(FRIDAY,),
)
DiaDeLaRaza = Holiday(
"Dia de la Raza",
month=10,
day=12,
observance=nearest_monday,
)
EvangelicalChurchDay = Holiday(
"Evangelical Church Day",
month=10,
day=31,
observance=tuesday_and_wednesday_to_friday,
start_date="2008",
)
AllSaintsDay = all_saints_day()
ImmaculateConception = immaculate_conception()
ChristmasEve = christmas_eve(days_of_week=WEEKDAYS)
Christmas = christmas()
DayBeforeBankHoliday = Holiday(
"Day Before Bank Holiday",
month=12,
day=30,
days_of_week=WEEKDAYS,
)
BankHoliday = new_years_eve()
class XSGOExchangeCalendar(ExchangeCalendar):
"""
Calendar for the Santiago Stock Exchange (Bolsa de Comercio de Santiago) in
Chile.
https://www.bolsadesantiago.com/mercado_horarios_feriados
Open Time: 9:30 AM, CLT/CLST (Chile Standard Time/Chile Summer Time)
Close Time: 4:00 PM, CLT (March to October)
5:00 PM, CLST (November to February)
Regularly-Observed Holidays:
- New Year's Day
- Good Friday
- Corpus Christi (until 2007, inclusive)
- Labour Day
- Navy Day
- Saint Peter and Saint Paul Day
- Feast Day of Our Lady of Mount Carmel (starting 2008)
- Assumption Day
- Independence Day
- Army Day
- Dia de la Raza
- Evangelical Church Day
- All Saints' Day
- Immaculate Conception
- Christmas Day
- Bank Holiday
Holidays No Longer Observed:
- N/A
Early Closes:
- Maundy Thursday
- Day before Independence Day
- Christmas Eve
- Day before Bank Holiday
"""
name = "XSGO"
tz = ZoneInfo("America/Santiago")
open_times = ((None, datetime.time(9, 30)),)
early_close_1230 = datetime.time(12, 30)
early_close_130 = datetime.time(13, 30)
@property
def close_times(self):
# The equity market close time changes twice per year. In March it
# changes to 4:00PM for winter and in November it changes to 5PM for
# summer.
return tuple(self._starting_dates_and_close_times())
@property
def regular_holidays(self):
return HolidayCalendar(
[
NewYearsDay,
GoodFriday,
MondayPriorToCorpusChristi,
LabourDay,
NavyDay,
NationalDayOfIndigenousPeoples,
SaintPeterAndSaintPaulDay,
OurLadyOfMountCarmelDay,
AssumptionDay,
PublicHolidayMonday,
IndependenceDay,
ArmyDay,
PublicHolidayFriday,
DiaDeLaRaza,
EvangelicalChurchDay,
AllSaintsDay,
ImmaculateConception,
Christmas,
BankHoliday,
]
)
@property
def adhoc_holidays(self):
return [
# Bicentennial Celebration.
pd.Timestamp("2010-09-17"),
pd.Timestamp("2010-09-20"),
# New Year's Day Observed. It is unclear why this happened only for
# this one year.
pd.Timestamp("2017-01-02"),
# Census Day.
pd.Timestamp("2017-04-19"),
# Pope Visit.
pd.Timestamp("2018-01-16"),
# Day off for National Day
pd.Timestamp("2022-09-16"),
]
@property
def special_closes(self):
return [
(
self.early_close_1230,
HolidayCalendar([ChristmasEve, DayBeforeBankHoliday]),
),
(
self.early_close_130,
HolidayCalendar([MaundyThursday, DayBeforeIndependenceDay]),
),
]
def _starting_dates_and_close_times(self):
yield ((None, datetime.time(17)))
for year in range(1980, 2050):
yield (pd.Timestamp(f"{year}-03-01"), datetime.time(16))
yield (pd.Timestamp(f"{year}-11-01"), datetime.time(17))