Add script to download historical tick data from Sierra Chart's DTC server
This commit is contained in:
parent
ab17f59778
commit
14a6973599
120
download_historical_tick_data.py
Normal file
120
download_historical_tick_data.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user