Login Page - Create Account

Support Board


Date/Time: Thu, 01 Jan 2026 17:11:48 +0000



Post From: Python for Sierra Chart

[2026-01-01 09:06:00]
User150671 - Posts: 70
Hope this helps, feel free to send me a message if you have any questions

# Scid File Operations
## Imports
# Files / System
import sys
from pathlib import Path
## Data
import numpy as np
import pandas as pd
## Time / Date
import datetime as dt
from zoneinfo import ZoneInfo # needed for timezone conversion if required. Available Zones: print(zoneinfo.available_timezones()) / https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

## function returns scidfile as a dataframe
def get_scid_df(scidfile, limitsize=sys.maxsize):
  f = Path(scidfile)
  assert f.exists(), "SCID file not found"
  # Check // set the size
  stat = f.stat()

  offset = 56 if stat.st_size < limitsize else stat.st_size - (
    (limitsize // 40) * 40)

  # rectype for DatFrame
  sciddtype = np.dtype([
    ('Time', '<u8'),
    ('Open', '<f4'),
    ('High', '<f4'),
    ('Low', '<f4'),
    ('Close', '<f4'),
    ('Trades','<i4'),
    ('Volume', '<i4'),
    ('BidVolume', '<i4'),
    ('AskVolume', '<i4'),
    ])

  df = pd.DataFrame(data=np.memmap(scidfile, dtype=sciddtype, offset=offset,mode="r"),copy=False)
  
  # Set the index columns and covert it to UTC time from Sierras Native Time
  df.set_index('Time', inplace=True)
  df.index = pd.to_datetime(df.index - 2209161600000000, unit='us').tz_localize(tz='utc')
  df.sort_index(inplace=True)
  return df

## function returns scidfile as a numpy array - quicker but less useful for some circumstances
def get_scid_np(scidfile, limitsize=sys.maxsize):
  # Check Path Exists
  f = Path(scidfile)
  assert f.exists(), f"SCID file not found: {scidfile}"
  # Check // set the size
  stat = f.stat()
  offset = 56 if stat.st_size < limitsize else stat.st_size - (
    (limitsize // 40) * 40)

  ### Setup the SCID dtype
  sciddtype = np.dtype([
    ('Time', '<u8'),
    ('Open', '<f4'),
    ('High', '<f4'),
    ('Low', '<f4'),
    ('Close', '<f4'),
    ('Trades','<i4'),
    ('Volume', '<i4'),
    ('BidVolume', '<i4'),
    ('AskVolume', '<i4'),
    ])

  scid = np.fromfile(scidfile, dtype=sciddtype, offset=offset)
  return scid


# takes a scid time and returns it as a dt.datetime
def time_from(sierratime):
  sierra_epoch = dt.datetime(1899, 12, 30, tzinfo=dt.timezone.utc)
  dtg = sierra_epoch + dt.timedelta(microseconds=int(sierratime))
  return dtg

# takes a dt.datetime object and returns it as a np.uint64 for working with scid files
def time_to(dtg):
  sierra_epoch = dt.datetime(1899, 12, 30, tzinfo=dt.timezone.utc)
  delta = dtg - sierra_epoch
  sierratime = np.uint64(delta.total_seconds()*1000000)
  return sierratime


## Example Usage
scidfile = 'c:/sierra/charts/data/ESH26-CME.scid'

## scicnp Opperations
scidnp = get_scid_np(scidfile)

# Get the last time from the SCID FIle
last_sierra_time = scidnp['Time'][-1]
# Convert that into a datetime object
last_dt_time = time_from(last_sierra_time)
# get the date of that object
last_date = last_dt_time.date()

# all three operations in one line:
last_date = time_from(scidnp['Time'][-1]).date()

# Now that we have a date to work on, we need to create datetime objects representing the start/end of the period we are looking
# I will use a full globex session as an example

# dt.datetime.combine takes a dt date object and a dt time object and converts it to a dattime object
# See Documentation here: https://docs.python.org/3/library/datetime.html
# as globex open is the prior day, we need to subtract 1 day from the last date, we do this using dt.imedelta(days=1) to get the last date
# as globex open is also in American Time we use a timezone native object set in US Time by specifying the timezone using tzinfo and ZoneInfo
# it is a good idea to use the correct timezone for the product you are looking at to make sure things are consistent
# e.g. if you are looking at say Bund I would use either a Berlin or London Time tzinfo=ZoneInfo('Europe/Berlin') / tzinfo=ZoneInfo('Europe/London') - London is still in Europe according to timezones.

globex_open = dt.datetime.combine(last_date-dt.timedelta(days=1),dt.time(18,0),tzinfo=ZoneInfo("America/New_York"))
globex_close = dt.datetime.combine(last_date,dt.time(17,0),tzinfo=ZoneInfo("America/New_York"))

# Now we get every entry in the numpy array where the Time is greater than Globex open and less than Globex Close
# calling the time_to function to convert the dattime objects to sierra times
window = scidnp[(scidnp['Time'] > time_to(globex_open)) & (scidnp['Time'] < time_to(globex_close))]



## Data Frame Operations
sciddf = get_scid_df(scidfile)

# As our function to get the dataframe converted the Sierra Time Object to a DateTime Index we can index quickly and efficently on the index
# The dataframe oindex in UTC time, however you can index in any timezone provided the start and end are in the same timezone
# to get the same window as on the np file we can slice the index as follows:
window = sciddf[globex_open:globex_close]


## Example of how to resample a dataframe inot a higher timeframe :
# the agg function is on the Close column instead of the Open/High/Low/Close columns due to the storage format used in scidfiles:
# Intraday Data File Format: Data Structures Used

df = sciddf.resample('1min', origin='start_day').agg({'Close': ['first','max', 'min', 'last'], 'Trades' : 'sum', 'Volume' : 'sum', 'BidVolume' : 'sum', 'AskVolume' : 'sum'}).dropna()
df.columns = ['Open', 'High', 'Low', 'Close', 'Trades','Volume','BidVolume','AskVolume']

# this is useful if you wnated to index of a specifc time as well - but that time may not have had trade at that exact milisecond.
# you could either iteratively set the window you want for every possible date... or you could just get every instance of that time in the dateframe:

# as an example:
cash_open_index = sciddf.loc[sciddf.index.tz_convert(ZoneInfo("America/New_York")).time == dt.time(9,30)].index # returns 9 instances and takes a while
cash_open_index = df.loc[df.index.tz_convert(ZoneInfo("America/New_York")).time == dt.time(9,30)].index # returns 23 instances very quickly

# we can then either call the dataframe with that index:
df.loc[cash_open_index]

# or we can iterate over that index as do more complex analysis:
for index in cash_open_index:
  time_end = dt.datetime.combine(index.date(),dt.time(9,35),tzinfo=ZoneInfo("America/New_York"))
  window = sciddf.loc[index:time_end]
  # do stuff here