Add script to download historical tick data from Sierra Chart's DTC server

This commit is contained in:
moshferatu 2023-09-22 08:36:08 -07:00
parent ab17f59778
commit 14a6973599

View File

@ -0,0 +1,120 @@
############################################################################################################
# Not using this as it turns out you can't download historical tick data from CME Group exchanges via DTC. #
# Reference: https://www.sierrachart.com/index.php?page=doc/DTCServer.php#Restrictions #
############################################################################################################
import socket
import json
from dotenv import load_dotenv
from os import getenv
load_dotenv()
# DTC Protocol Constants
ENCODING_REQUEST = 6
HISTORICAL_PRICE_DATA_REQUEST = 800
INTERVAL_TICK = 0
LOGON_REQUEST = 1
LOGON_RESPONSE = 2
LOGON_SUCCESS = 1
NULL_TERMINATOR = b'\x00'
class EncodingRequest:
def __init__(self):
self.Type = ENCODING_REQUEST
self.ProtocolVersion = 8 # Set desired DTC Protocol version.
self.Encoding = 2 # Set desired encoding (JSON).
self.ProtocolType = 'DTC'
def to_json(self):
return json.dumps(self.__dict__)
class LogonRequest:
def __init__(self, username, password):
self.Type = LOGON_REQUEST
self.ProtocolVersion = 8 # Set desired DTC Protocol version.
self.Username = username
self.Password = password
self.HeartbeatIntervalInSeconds = 30
self.ClientName = 'Python DTC Client'
def to_json(self):
return json.dumps(self.__dict__)
def authenticate_with_sierra_chart(client, username, password):
print('Sending Encoding Request')
encoding_request = EncodingRequest()
encoded_request = encoding_request.to_json().encode() + NULL_TERMINATOR
client.sendall(encoded_request)
encoding_response = client.recv(4096).decode().rstrip(NULL_TERMINATOR)
print('Encoding Response: ', encoding_response)
print('Sending Logon Request')
logon_request = LogonRequest(username, password)
encoded_request = logon_request.to_json().encode('ascii') + NULL_TERMINATOR
client.sendall(encoded_request)
response = client.recv(4096).decode().rstrip(NULL_TERMINATOR)
print('Logon Response: ', response)
data = json.loads(response)
return data['Type'] == LOGON_RESPONSE and data.get('Result', -1) == LOGON_SUCCESS
class HistoricalPriceDataRequest:
def __init__(self, symbol, exchange, start_date, end_date):
self.Type = HISTORICAL_PRICE_DATA_REQUEST
self.RequestID = 1
self.Symbol = symbol
self.Exchange = exchange
self.RecordInterval = INTERVAL_TICK
self.StartDateTime = start_date
self.EndDateTime = end_date
self.MaxDaysToReturn = 0
self.UseZLibCompression = 1
self.RequestDividendAdjustedStockData = 0
def to_json(self):
return json.dumps(self.__dict__)
def listen_for_messages(client):
messages = []
while True:
response = client.recv(4096).decode().rstrip(NULL_TERMINATOR)
if not response:
break
data = json.loads(response)
messages.append(data)
if data['Type'] != 701: # "Waiting" message.
break
return messages
def request_data_from_sierra_chart(host, port, symbol, exchange, start_date, end_date):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
if not authenticate_with_sierra_chart(client, getenv('SIERRA_CHART_USERNAME'), getenv('SIERRA_CHART_PASSWORD')):
print('Authentication failed.')
client.close()
return
request = HistoricalPriceDataRequest(symbol, exchange, start_date, end_date)
encoded_request = request.to_json().encode() + NULL_TERMINATOR
client.sendall(encoded_request)
messages = listen_for_messages(client)
for message in messages:
print(message) # Store this data or process it as needed.
client.close()
if __name__ == '__main__':
HOST = '127.0.0.1'
PORT = 11098 # Default DTC Protocol port for historical data.
SYMBOL = 'MYMZ22-CBOT'
EXCHANGE = 'CBOT'
START_DATE = 20221001000000 # YYYYMMDDHHMMSS
END_DATE = 20221001235959
request_data_from_sierra_chart(HOST, PORT, SYMBOL, EXCHANGE, START_DATE, END_DATE)