Calendars & timezones#

Introduction#

This page demonstrates how to configure the timezone and calendar features when initializing your environment. It also explains how to search and work with the schedule and calendar functions available within th SigTech framework.

This information is particularly valuable for any SigTech user wanting to build strategies which trade outside of the UTC timezone and trading calendar.

Environment#

When initializing your environment with the sig.init() command, calendar and timezone settings will be configured by default.

Learn more: Configuration parameters.

import sigtech.framework as sig
import datetime as dtm
import pandas as pd
import numpy as np

sig.init()

TradingManager#

A TradingManager object is automatically created during environment initialization. These objects manage calendar, timezone and open/close time information for strategies. They also provide a collection of useful trading functionalities. Configuration parameters including the initials TM are referencing the TradingManager.

Relevant defaults#

Parameter

Default

TM_CALENDAR

‘None’

TM_TIMEZONE

‘Europe/London’

TM_OPEN

datetime.time(7, 30, 0)

TM_CLOSE

datetime.time(18, 0, 0)

TM_DEFAULT___DATA_POINTS

[DataPoints.LONDON_1600, DataPoints.LAST]

TM_INTRADAY__OUT__OF_HOURS

False

Available options#

Timezones#

Available timezones are included in the standard Python time zone library, pytz. To generate a list of the available options, you can run the following command:

import pytz
pytz.all_timezones

Calendars#

Available calendars are listed in the Calendars folder of our Data browser. The object name can be retrieved from the VIEW DETAILS page, under CODE EXAMPLE.

The most commonly used calendars are:

'BANGKOK': 'BANGKOKB CALENDAR',
'BUDAPEST': 'BUDAPESTB CALENDAR',
'HONG KONG': 'HONGKONGB CALENDAR',
'ISTANBUL': 'ISTANB CALENDAR',
'JOHANNESBURG': 'JOHANNESBB CALENDAR',
'LONDON': 'LONDONB CALENDAR',
'MEXICO CITY': 'MEXICOB CALENDAR',
'MOSCOW': 'MOSCOWB CALENDAR',
'MUMBAI': 'MUMBAIB CALENDAR',
'NEW YORK': 'FEDFUND CALENDAR',
'OSLO': 'OSLOB CALENDAR',
'PARIS': 'PARISB CALENDAR',
'SEOUL': 'SEOULB CALENDAR',
'SINGAPORE': 'SINGAPOREB CALENDAR',
'STOCKHOLM': 'STOCKHOLMB CALENDAR',
'SYDNEY': 'SYDNEYB CALENDAR',
'TARGET': 'TARGET CALENDAR',
'EUR': 'TARGET CALENDAR',
'TOKYO': 'TOKYOB CALENDAR',
'TORONTO': 'TORONTOB CALENDAR',
'WARSAW': 'WARSAWB CALENDAR',
'WELLINGTON': 'WELLINGTB CALENDAR',
'USD': 'FEDFUND CALENDAR',
'ZURICH': 'ZURICHB CALENDAR'

The Data Browser lists all available calendars, and provides sample code showing how to get them. For example, to get the A2X South Africa calendar:

calendar = sig.obj.get("A2XSE(T) CALENDAR")

# Description
print(calendar.description)

# List all holidays
print(calendar.holidays)

We also have a few classes that represent calendar objects, including:

  • AuctionCalendar

  • EconomicCalendar

  • HolidayCalendar

  • ModifiedHolidayCalendar: Use the add_holidays and remove_holidays parameters to modify the underlying calendar

FX market currency pairs#

To identify relevant calendars for currency pairs, use FXMarket.instance() to retrieve specific schedules.

Input:

from sigtech.framework.infra.analytics.fx.fx_market import FXMarket

FXMarket.instance().schedule_stub('HKD', 'USD').holidays

Output:

'HKD CALENDAR,WMCO CALENDAR'

Exchange & OTC calendars#

For futures based strategies, you can retrieve exchange calendars directly from the futures group with the following code:

Input:

start_date = dtm.date(2010, 1, 4)

strategy = sig.RollingFutureStrategy(
    currency='USD',
    start_date=start_date,
    contract_code='GC',
    contract_sector='COMDTY',
    rolling_rule='front',
    front_offset='-5:-4',
    total_return=False,
    include_trading_costs=False
)
strategy.contract_group.holidays

Output:

'CMECOMF(T) CALENDAR'

You can then retrieve their relevant holiday calendars:

Input:

sig.obj.get('COU21 COMDTY').group().holidays

Output:

'ICE_EU_IPE(T) CALENDAR'

For equities based strategies, you can retrieve exchange calendars with the following command:

holiday_calendar = sig.obj.get('1000045.SINGLE_STOCK.TRADABLE').exchange().holidays

For business days, you will need to fetch the holiday_calendar object and then call business_days, specifying a start and end date:

business_days = sig.obj.get(holiday_calendar).business_days(
    start=dtm.date(2020, 1, 1),
    end=dtm.date(2022, 3, 15)
)

OTC instruments contain a .holidays method which retrieves the relevant calendars without the need for calling sig.obj.get:

Input:

irs = sig.InterestRateSwap(currency='USD',
                           trade_date=dtm.date(2017, 4, 14),
                           start_date=dtm.date(2017, 5, 3),
                           tenor='5Y')
irs.history();
irs.holidays

Output:

'FEDFUND, LONDONB CALENDAR'

Changing the default values#

You can reconfigure the calendar and timezone values during initialization. If you have already initialized your environment, the sig.de_init() call will allow you to reset the values. The following code block will change the defaults:

# Destroy your environment
sig.de_init()

# Reconfigure your environment
env = sig.init()
sig.config.set('TM_TIMEZONE', 'Asia/Tokyo')
sig.config.set('TM_CALENDAR', 'HKD CALENDAR')

This code block can be used if you’re initializing the environment for the first time—simply remove the sig.de_init() command.

You can check these changes have been successful by running the following commands:

Input:

env[sig.config.TM_TIMEZONE]

Output:

'Asia/Tokyo'

Input:

env[sig.config.TM_CALENDAR]

Output:

'HKD CALENDAR'

Adjusting the date#

You can add or adjust business day conventions, and retrieve month-end and International Monetary Market (IMM) dates using sig.calendar.

Add business days:

Input:

sig.calendar.date_increment(
    dtm.date(2021, 12, 1),
    '1W',
    calendar='HKD CALENDAR',
    bdc='FOLLOWING'
)

Output:

datetime.date(2021, 12, 8)

Add month end dates:

Input:

sig.calendar.get_month_end_dates(
    start=dtm.date(2021, 9, 1),
    end=dtm.date(2022, 1, 3),
    calendar_names='WMCO CALENDAR'
)

Output:

[datetime.date(2021, 9, 30),
 datetime.date(2021, 10, 29),
 datetime.date(2021, 11, 30),
 datetime.date(2021, 12, 31)]

Add IMM dates:

Input:

sig.calendar.imm_date(ref_date=dtm.date.today(), currency='USD')

Output:

datetime.date(2022, 6, 15)

Rebalancing frequencies#

SigTech supports the majority of common rebalancing schedules.

Using a BasketStrategy as an example, the AVAILABLE_REBALANCE_FREQS object can help you to locate the correct string to supply for rebalancing.

Input:

freqs = sig.BasketStrategy.AVAILABLE_REBALANCE_FREQS
frequencies = [f for f in dir(freqs) if not f.startswith('_')]
frequency_strings = sorted([f for f in frequencies if f == f.upper()])
frequency_strings

Output:

['END_OF_MONTH', 'IMM', 'START_OF_MONTH', 'YEARLY']

You can use the values outputted above to determine the correct input string:

Input:

print(freqs.END_OF_MONTH)
print(freqs.IMM)
print(freqs.START_OF_MONTH)
print(freqs.YEARLY)

Output:

EOM
3M_IMM
SOM
YEARLY

Input:

frequency_methods = sorted([f for f in frequencies if f == f.lower()])
frequency_methods

Output:

['business_days',
 'day_of_month',
 'fridays',
 'mondays',
 'months',
 'thursdays',
 'tuesdays',
 'wednesdays',
 'weeks']

The values outputted above are methods that take an input and return the correct string format. You can use the thursdays method as an example:

Input:

freqs.thursdays?

Output:

Signature: freqs.thursdays(n=1)
Docstring:
Rebalance every ``n`` weeks on Thursdays.

:param n: Number of weeks, 1 by default.
:return: Rebalance string value.
File:      /opt/conda/envs/sig-env/lib/python3.7/site-packages/sigtech/framework/schedules/schedule.py
Type:      method

The input n determines how often, in terms of weeks, to rebalance. For instance, freqs.thursdays(2) returns the string to input to rebalance a strategy every second Thursday.

The following cell block runs some of these methods and outputs the strings necessary for the rebalancing_frequency.

Input:

print(freqs.business_days(2))
print(freqs.day_of_month(2))
print(freqs.fridays(2))
print(freqs.thursdays(2))
print(freqs.weeks(2))

Output:

2BD
2DOM
2W-FRI
2W-THU
2W

Custom schedules#

SigTech includes a range of rebalancing schedules, such as: EOD, 1W, 2W, 1M, SOM, EOD, 2BD, 2DOM, 2W-FRI, 2W-THU, 2W.

The rebalancing schedules listed above are not exhaustive. The Rebalancing frequencies section of this page provides the necessary code to list all of the available options.

If your desired rebalancing frequency is unavailable, you can use the SchedulePeriodic class to create a custom schedule. The following example creates a custom schedule that rebalances every third Friday at a quarterly frequency:

Python:

from sigtech.framework.schedules import SchedulePeriodic

end_date = dtm.date(2021, 5, 14)
frequency = '1W-Fri'

custom_schedule = SchedulePeriodic(
    start_date=start_date,
    end_date=end_date,
    holidays='NYSE(T) CALENDAR',
    frequency=frequency,
).all_data_dates()

custom_schedule = [x for x in custom_schedule
                   if x.month in [3, 6, 9, 12]]  # Quarterly rebalancing
custom_schedule = [x for x in custom_schedule
                   if x.day >= 15 and x.day <= 21]  # third Friday
custom_schedule[-5:]

Output:

[datetime.date(2020, 3, 20),
 datetime.date(2020, 6, 19),
 datetime.date(2020, 9, 18),
 datetime.date(2020, 12, 18),
 datetime.date(2021, 3, 19)]