AHL Research Versioned TimeSeries and Tick store for high-performance financial data storage and analysis
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive date/time handling for financial data including timezone management, date range operations, and time series utilities. Provides robust datetime conversion and time-based data filtering capabilities optimized for financial market data across global timezones.
Date/time range specification for queries and temporal operations with support for various boundary types.
class DateRange:
"""
Date/time range specification with configurable boundaries.
Supports various boundary types (open/closed intervals) and
step specifications for time series operations and queries.
"""
def __init__(self, start=None, end=None, interval=CLOSED_CLOSED):
"""
Create date range with configurable boundary types.
Parameters:
- start: Start datetime or date-like object (default: None for unbounded)
- end: End datetime or date-like object (default: None for unbounded)
- interval: Boundary type (CLOSED_CLOSED, OPEN_CLOSED, etc.)
"""Functions for converting between different datetime representations and formats.
def datetime_to_ms(dt):
"""
Convert datetime to milliseconds since Unix epoch.
Parameters:
- dt: datetime object to convert
Returns:
int: Milliseconds since epoch (1970-01-01 00:00:00 UTC)
"""
def ms_to_datetime(ms):
"""
Convert milliseconds since epoch to datetime object.
Parameters:
- ms: Milliseconds since Unix epoch
Returns:
datetime: UTC datetime object
"""
def to_dt(date):
"""
Convert various date representations to datetime object.
Parameters:
- date: Date string, timestamp, or date-like object
Returns:
datetime: Standardized datetime object
Raises:
- ValueError: If date format cannot be parsed
"""Functions for handling timezone conversions and timezone-aware datetime operations.
def mktz(timezone):
"""
Create timezone object from string specification.
Parameters:
- timezone: Timezone string (e.g., 'UTC', 'US/Eastern', 'Europe/London')
Returns:
pytz.timezone: Timezone object for datetime operations
Raises:
- TimezoneError: If timezone string is invalid
"""
def utc_dt_to_local_dt(dt, local_tz):
"""
Convert UTC datetime to local timezone.
Parameters:
- dt: UTC datetime object
- local_tz: Target timezone object or string
Returns:
datetime: Datetime converted to local timezone
"""Functions for parsing and converting date range specifications.
def string_to_daterange(string):
"""
Parse date range from string representation.
Parameters:
- string: Date range string (various formats supported)
Returns:
DateRange: Parsed date range object
Raises:
- ValueError: If string format cannot be parsed
"""
def to_pandas_closed_closed(date_range):
"""
Convert DateRange to pandas-compatible closed interval.
Parameters:
- date_range: DateRange object to convert
Returns:
pandas-compatible date range with closed boundaries
"""Constants defining different types of interval boundaries for date ranges.
OPEN_CLOSED = "open_closed" # Excludes start, includes end: (start, end]
CLOSED_OPEN = "closed_open" # Includes start, excludes end: [start, end)
OPEN_OPEN = "open_open" # Excludes both boundaries: (start, end)
CLOSED_CLOSED = "closed_closed" # Includes both boundaries: [start, end]Timezone-related exception for error handling.
class TimezoneError(Exception):
"""
Exception raised for timezone-related errors.
Raised when timezone strings cannot be parsed or
timezone conversions fail.
"""from arctic.date import DateRange, CLOSED_CLOSED, OPEN_CLOSED, CLOSED_OPEN
from datetime import datetime, timedelta
# Create date ranges
start_date = datetime(2020, 1, 1, 9, 30) # Market open
end_date = datetime(2020, 1, 1, 16, 0) # Market close
# Trading session range (includes both boundaries)
session_range = DateRange(start_date, end_date, CLOSED_CLOSED)
# Date range excluding end boundary
hourly_range = DateRange(
datetime(2020, 1, 1),
datetime(2020, 1, 7),
CLOSED_OPEN
)
# Month range
month_range = DateRange(
datetime(2020, 1, 1),
datetime(2020, 2, 1),
CLOSED_CLOSED
)
print(f"Session range: {session_range}")
print(f"Monthly range: {month_range}")from arctic.date import datetime_to_ms, ms_to_datetime, to_dt
# Convert datetime to milliseconds
trade_time = datetime(2020, 1, 15, 14, 30, 45)
ms_timestamp = datetime_to_ms(trade_time)
print(f"Timestamp in ms: {ms_timestamp}")
# Convert back to datetime
restored_time = ms_to_datetime(ms_timestamp)
print(f"Restored datetime: {restored_time}")
# Convert various date formats
date_formats = [
"2020-01-15",
"2020-01-15 14:30:45",
"01/15/2020",
1579097445000, # milliseconds
datetime(2020, 1, 15)
]
for date_input in date_formats:
try:
converted = to_dt(date_input)
print(f"'{date_input}' -> {converted}")
except ValueError as e:
print(f"Failed to convert '{date_input}': {e}")from arctic.date import mktz, utc_dt_to_local_dt
import pytz
# Create timezone objects
utc_tz = mktz('UTC')
ny_tz = mktz('US/Eastern')
london_tz = mktz('Europe/London')
tokyo_tz = mktz('Asia/Tokyo')
print(f"UTC timezone: {utc_tz}")
print(f"New York timezone: {ny_tz}")
# Convert UTC time to different timezones
utc_time = datetime(2020, 1, 15, 19, 30, 0, tzinfo=pytz.UTC)
ny_time = utc_dt_to_local_dt(utc_time, ny_tz)
london_time = utc_dt_to_local_dt(utc_time, london_tz)
tokyo_time = utc_dt_to_local_dt(utc_time, tokyo_tz)
print(f"UTC time: {utc_time}")
print(f"New York time: {ny_time}")
print(f"London time: {london_time}")
print(f"Tokyo time: {tokyo_time}")# Define market sessions across different timezones
market_sessions = {
'NYSE': {
'open': datetime(2020, 1, 15, 14, 30), # 9:30 AM EST in UTC
'close': datetime(2020, 1, 15, 21, 0) # 4:00 PM EST in UTC
},
'LSE': {
'open': datetime(2020, 1, 15, 8, 0), # 8:00 AM GMT in UTC
'close': datetime(2020, 1, 15, 16, 30) # 4:30 PM GMT in UTC
},
'TSE': {
'open': datetime(2020, 1, 15, 0, 0), # 9:00 AM JST in UTC
'close': datetime(2020, 1, 15, 6, 0) # 3:00 PM JST in UTC
}
}
# Create date ranges for each market session
for market, times in market_sessions.items():
session = DateRange(times['open'], times['close'])
duration = times['close'] - times['open']
print(f"{market} session: {session} (Duration: {duration})")
# Weekly trading range (Monday to Friday)
week_start = datetime(2020, 1, 13) # Monday
week_end = datetime(2020, 1, 17) # Friday
trading_week = DateRange(week_start, week_end)
# Exclude weekends for continuous trading data
weekdays_only = DateRange(week_start, week_end, step=timedelta(days=1))from arctic.date import string_to_daterange, to_pandas_closed_closed
# Parse various date range string formats
date_strings = [
"2020-01-01 to 2020-01-31",
"Jan 1 2020 - Jan 31 2020",
"2020-01-01/2020-01-31",
"20200101:20200131"
]
for date_str in date_strings:
try:
parsed_range = string_to_daterange(date_str)
print(f"Parsed '{date_str}' -> {parsed_range}")
except ValueError as e:
print(f"Failed to parse '{date_str}': {e}")
# Convert to pandas-compatible format
date_range = DateRange(datetime(2020, 1, 1), datetime(2020, 1, 31))
pandas_range = to_pandas_closed_closed(date_range)
print(f"Pandas-compatible range: {pandas_range}")from arctic import Arctic, VERSION_STORE
import pandas as pd
# Setup for date-filtered queries
arctic_conn = Arctic('mongodb://localhost:27017')
lib = arctic_conn['market_data']
# Create sample data with timezone-aware timestamps
dates = pd.date_range('2020-01-01 09:30:00',
'2020-01-01 16:00:00',
freq='1min', tz='US/Eastern')
market_data = pd.DataFrame({
'price': np.random.randn(len(dates)).cumsum() + 100,
'volume': np.random.randint(100, 1000, len(dates))
}, index=dates)
# Write data
lib.write('AAPL', market_data)
# Query using date ranges
morning_session = DateRange(
datetime(2020, 1, 1, 9, 30),
datetime(2020, 1, 1, 12, 0)
)
afternoon_session = DateRange(
datetime(2020, 1, 1, 12, 0),
datetime(2020, 1, 1, 16, 0)
)
# Read data for specific sessions
morning_data = lib.read('AAPL', date_range=morning_session)
afternoon_data = lib.read('AAPL', date_range=afternoon_session)
print(f"Morning data points: {len(morning_data.data)}")
print(f"Afternoon data points: {len(afternoon_data.data)}")# Working with different boundary types
inclusive_range = DateRange(
datetime(2020, 1, 1, 9, 30),
datetime(2020, 1, 1, 16, 0)
) # Default: CLOSED_CLOSED [start, end]
# Exclude end boundary for non-overlapping ranges
exclusive_end = DateRange(
datetime(2020, 1, 1, 9, 30),
datetime(2020, 1, 1, 16, 0)
) # Can be configured as CLOSED_OPEN [start, end)
# Multiple non-overlapping ranges for batch processing
batch_ranges = []
start = datetime(2020, 1, 1)
for i in range(7): # One week of daily ranges
day_start = start + timedelta(days=i)
day_end = day_start + timedelta(days=1)
batch_ranges.append(DateRange(day_start, day_end))
for i, day_range in enumerate(batch_ranges):
print(f"Day {i+1}: {day_range}")
# Handle timezone-aware operations
utc_now = datetime.now(pytz.UTC)
local_tz = mktz('US/Pacific')
local_now = utc_dt_to_local_dt(utc_now, local_tz)
print(f"UTC time: {utc_now}")
print(f"Pacific time: {local_now}")Install with Tessl CLI
npx tessl i tessl/pypi-arctic