- 金融科技
- 科学计算
【免费下载链接】tf-quant-finance
High-performance TensorFlow library for quantitative finance.
导读
WeekendMask是 tf-quant-finance 日期模块(tff.datetime)中用于声明"一周内哪些天算作周末"的核心常量类。在构建HolidayCalendar(假日日历)时,通过weekend_mask参数传入掩码即可让工作日计算、日期滚动(roll)与息票/期限日程(schedule)自动跳过周末。读完本文,你将掌握WeekendMask四个预置掩码的确切语义、与WeekDay的索引对齐关系,以及如何在create_holiday_calendar、PeriodicSchedule等场景中组合使用它与自定义掩码。
WeekendMask 是什么
WeekendMask定义于日期模块的常量文件中(tf_quant_finance/datetime/constants.py),其官方 API 文档(api_docs/tf_quant_finance/datetime/WeekendMask.md)给出的描述是:"Provides weekend masks for some of the common weekend patterns."(为一些常见周末模式提供周末掩码)。
在 tf-quant-finance 中,周末被当作一种特殊的节假日处理——抽象基类HolidayCalendar的文档明确指出 "Weekends are treated as holidays"(周末视同节假日)。因此,一个掩码本质上定义了每个日历日是否是"工作日"的基准规则,再叠加法定节假日后,就构成了完整的非交易日集合。
WeekendMask虽然名称像枚举,但其源码实现是一个普通类,四个类属性各是一个长度为 7 的整数元组(0 表示工作日,1 表示休息日),索引 0 对应周一:
| 类变量 | 掩码值(周一→周日) | 适用地区(源码注释) | 语义 |
|---|---|---|---|
SATURDAY_SUNDAY | (0, 0, 0, 0, 0, 1, 1) | 美、英、欧洲等("US/UK/Europe etc.") | 周六、周日为周末 |
FRIDAY_SATURDAY | (0, 0, 0, 0, 1, 1, 0) | 中东多数国家("Most countries in the Middle East") | 周五、周六为周末,周日是工作日 |
SUNDAY_ONLY | (0, 0, 0, 0, 0, 0, 1) | 印度、尼泊尔("India, Nepal") | 仅周日为周末 |
NONE | (0, 0, 0, 0, 0, 0, 0) | 默认值("Default value") | 无周末,一周七天都是工作日 |
与 WeekDay 枚举的索引对齐
掩码的索引约定与同文件中的WeekDay枚举完全一致(constants.py):MONDAY = 0、TUESDAY = 1、WEDNESDAY = 2、THURSDAY = 3、FRIDAY = 4、SATURDAY = 5、SUNDAY = 6,即"周一起始、零基编号"。因此FRIDAY_SATURDAY = (0,0,0,0,1,1,0)中位置 4、5 的两个 1 恰好对应周五(FRIDAY)与周六(SATURDAY)。这一约定贯穿整个日期模块,自定义掩码时必须遵循,否则掩码会整体错位。
源码实现:掩码如何进入日历
类定义本体
WeekendMask的完整源码仅一个类、四个元组属性,没有任何方法(constants.py):
class WeekendMask(object): """Provides weekend masks for some of the common weekend patterns.""" # E.g. US/UK/Europe etc. SATURDAY_SUNDAY = (0, 0, 0, 0, 0, 1, 1) # E.g. Most countries in the Middle East. FRIDAY_SATURDAY = (0, 0, 0, 0, 1, 1, 0) # E.g. India, Nepal. SUNDAY_ONLY = (0, 0, 0, 0, 0, 0, 1) # Default value. NONE = (0, 0, 0, 0, 0, 0, 0)它没有继承enum.Enum,而是普通object子类;取值用 0/1 而非True/False,但下游 API 一律以布尔语义解释(1/True 表示休息日)。这也是为什么它能与用户自定义的[0,0,0,0,1,0,1]这类列表/Tensor 自由混用——create_holiday_calendar的weekend_mask参数接受的正是"任意可转换为 7 元素 Tensor 的对象"。
通过工厂函数进入 HolidayCalendar
掩码的唯一正式入口是create_holiday_calendar(holiday_calendar_factory.py):
def create_holiday_calendar( weekend_mask=None, holidays=None, start_year=None, end_year=None): ...其中weekend_mask的官方定义为:布尔Tensor,共 7 个元素、每个元素对应一周中的一天,索引 0 为周一;True表示该天是周末,False表示工作日;默认None表示不应用任何周末。
工厂内部(holiday_calendar_factory.py)会根据是否提供了holidays或start_year/end_year边界,选择性能更优的BoundedHolidayCalendar(预计算整张工作日查询表)或更灵活的UnboundedHolidayCalendar。两种实现都会消费weekend_mask:
BoundedHolidayCalendar(bounded_holiday_calendar.py):构造时执行
tf.convert_to_tensor(weekend_mask or constants.WeekendMask.NONE),即不传掩码时自动落到WeekendMask.NONE;随后在_compute_is_bus_day_table中(bounded_holiday_calendar.py)通过week_days = (ordinals - 1) % 7计算星期并tf.gather(self._weekend_mask, week_days)标记休息日,再以tf.bitwise.bitwise_or叠加法定节假日,最终生成按 ordinal 索引的is_bus_day查询表。UnboundedHolidayCalendar(unbounded_holiday_calendar.py):将掩码
tf.cast(..., dtype=tf.bool)后交给holiday_utils.business_day_mappers构造"工作日空间"与 ordinal 空间的互映射(holiday_utils.py),其中用tf.roll(weekend_mask, -_DAYOFWEEK_0, axis=0)调整掩码对齐后做工作日偏移累计。
从源码结构可以推断:掩码直接决定了"工作日空间"的密度与形状——例如FRIDAY_SATURDAY下工作日是 5 天/周但落在周日~周四,SUNDAY_ONLY下工作日是 6 天/周。所有基于日历的日期加减、滚动都在这套空间中进行,因此掩码选错会系统性影响全部计算结果。
实战一:创建不同地区的假日日历
最典型的用法是把掩码作为weekend_mask传入create_holiday_calendar,再配合holidays传入法定节假日列表。参考 holiday_calendar_test.py 的测试模式:
import tf_quant_finance as tff dates = tff.datetime # 美式日历:周六周日为周末,叠加元旦与圣诞节 cal = dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY, holidays=[(2020, 1, 1), (2020, 12, 25), (2021, 1, 1)]) date_tensor = dates.dates_from_tuples([(2020, 1, 1), (2020, 5, 1), (2020, 12, 25), (2021, 3, 8), (2021, 1, 1)]) cal.is_business_day(date_tensor) # 输出: [False, True, False, True, False] # 元旦 工作日 圣诞 工作日 元旦若把掩码换成中东模式:
cal_me = dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.FRIDAY_SATURDAY, start_year=2020, end_year=2021)此时周五、周六被判定为非工作日,而周日反而是工作日——这正是FRIDAY_SATURDAY的核心价值。
自定义掩码:打破"周六周日"假设
仓库测试明确支持自定义掩码(holiday_calendar_test.py):
# 周六上班、周五和周日休息 weekend_mask = [0, 0, 0, 0, 1, 0, 1] cal = dates.create_holiday_calendar( weekend_mask=weekend_mask, start_year=2020, end_year=2021) d = dates.dates_from_tuples([(2020, 1, 2), (2020, 1, 3), # 周四、周五 (2020, 1, 4), (2020, 1, 5), # 周六、周日 (2020, 1, 6), (2020, 5, 1), # 周一、周五 (2020, 5, 2)]) # 周六 cal.is_business_day(d) # 输出: [True, False, True, False, True, False, True]自定义掩码需满足:长度恰好为 7、索引 0 为周一、1 表示休息日。它可以是 Python 列表、NumPy 数组或tf.Tensor,工厂与两种日历实现都会自动做类型转换。
实战二:与日程生成(Schedule)配合
WeekendMask并不只服务于"判断某天是否营业",它是整个业务日程系统的地基。在 schedules_test.py 中,PeriodicSchedule(周期日程,如付息日序列)正是通过掩码构建日历:
actual_schedule = dates.PeriodicSchedule( start_date=start_dates, end_date=end_dates, tenor=tenors, holiday_calendar=dates.create_holiday_calendar( weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY, start_year=2020, end_year=2028), roll_convention=dates.BusinessDayConvention.MODIFIED_FOLLOWING, backward=backward, end_of_month=end_of_month).dates()同样,BusinessDaySchedule(纯工作日日程)也接受携带掩码的日历(schedules_test.py)。可见,WeekendMask与BusinessDayConvention(滚动约定,如FOLLOWING、MODIFIED_FOLLOWING)是一对固定搭档:掩码决定"哪些天要滚",约定决定"往哪个方向滚、如何避开跨月"。当掩码改变周末定义时,同一组日期在roll_to_business_day、add_business_days等 API(定义于 holiday_calendar.py 的抽象基类)下的滚动结果会相应变化。
注意事项与最佳实践
NONE是默认兜底值:create_holiday_calendar与BoundedHolidayCalendar在weekend_mask=None时都自动回落到WeekendMask.NONE(bounded_holiday_calendar.py),此时一周七天全是工作日。需要周末过滤时必须显式传掩码。- 索引从周一开始:与 Python
datetime约定(datetime.weekday():周一=0)一致,但注意WeekDay枚举与 ISO 8601(周日=7)不同,自定义掩码时最容易踩的坑就是按"周日开头"排列 0/1。 - 掩码负责周末,
holidays负责法定节假日:两者通过tf.bitwise.bitwise_or叠加。官方建议在提供holidays时注意把落在周末的节日人工调整(如 2021-12-25 圣诞落在周六时调整为 12-24),或直接借助 Pandas 的AbstractHolidayCalendar生成(参见 create_holiday_calendar.md 与 holiday_calendar_factory.py 中的示例)。 - 提供边界以换取性能:
create_holiday_calendar文档明确提示,给出holidays和/或start_year/end_year会得到性能更好的BoundedHolidayCalendar;同时每个日历实例应在单个计算图/tf.function 上下文中使用。 - 测试覆盖可靠:holiday_calendar_test.py 中的
test_both_impls装饰器保证每个行为在BoundedHolidayCalendar与UnboundedHolidayCalendar两种实现上结果一致,说明掩码语义在两条实现路径上是等价且被持续验证的。
结语
WeekendMask虽小,却是 tf-quant-finance 日期体系中"周末定义"的唯一事实来源。四个预置掩码覆盖了全球主流交易市场的周末结构(六日休、周五六休、仅周日休、无周末),而自定义掩码机制让任意地区的特殊周末安排都能以一行元组表达。理解其索引约定与在HolidayCalendar内部的消费方式,是正确开展业务日计算、付息日程生成与日期滚动的前提。
- 金融科技
- 科学计算
【免费下载链接】tf-quant-finance
High-performance TensorFlow library for quantitative finance.
相关推荐
tf-quant-finance 日期模块 HolidayCalendar 深入指南:节假日日历与工作日滚动约定
tf quant finance 日期模块 HolidayCalendar 深入指南:节假日日历与工作日滚动约定 HolidayCalendar 是 tf qu
金融科技科学计算tf-quant-finance datetime 模块完全指南:DateTensor、PeriodTensor、假日日历与 Day Count 实践
tf quant finance datetime 模块完全指南:DateTensor、PeriodTensor、假日日历与 Day Count 实践 tf_q
金融科技科学计算tf-quant-finance 周期日期调度(PeriodicSchedule)实战指南:日期序列生成、假日调整与批量调度
tf quant finance 周期日期调度(PeriodicSchedule)实战指南:日期序列生成、假日调整与批量调度 导读 本文围绕 tf quant
金融科技科学计算
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考