Skip to content
This repository was archived by the owner on Nov 18, 2024. It is now read-only.

Commit 31e438b

Browse files
committed
Trade streaming & Terminal level improvements.
1 parent 039bfe5 commit 31e438b

File tree

6 files changed

+113
-103
lines changed

6 files changed

+113
-103
lines changed

docs/options/open_interest_streaming.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ def streaming():
55
# Credentials now required because get_last is only available to ThetaData Standard & Pro subscribers.
66
client = ThetaClient(username="MyThetaDataEmail", passwd="MyThetaDataPassword")
77

8-
with client.connect_stream(callback):
9-
# requests every option open interest update
10-
client.req_full_open_interest_stream()
8+
client.connect_stream(callback) # You can stop streaming by calling client.close_stream
9+
client.req_full_open_interest_stream() # requests every option open interest update
1110

1211

1312
# User generated method that gets called each time a message from the stream arrives.

docs/options/trade_streaming.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
from datetime import date
2+
from time import sleep
3+
24
from thetadata import ThetaClient, OptionRight, StreamMsg, StreamMsgType
35

46

57
def streaming():
68
# Credentials now required because get_last is only available to ThetaData Standard & Pro subscribers.
79
client = ThetaClient(username="MyThetaDataEmail", passwd="MyThetaDataPassword")
810

9-
with client.connect_stream(callback):
10-
client.req_trade_stream_opt("NVDA", date(2022, 12, 23), 150, OptionRight.CALL)
11-
client.req_trade_stream_opt("NVDA", date(2022, 12, 23), 150, OptionRight.PUT)
12-
client.req_trade_stream_opt("NVDA", date(2022, 12, 23), 145, OptionRight.CALL)
13-
client.req_trade_stream_opt("NVDA", date(2022, 12, 23), 145, OptionRight.PUT)
11+
client.connect_stream(callback) # You can stop streaming by calling client.close_stream
12+
# This contract is likely expired! Replace it with a contract that isn't expired
13+
client.req_trade_stream_opt("NVDA", date(2023, 1, 13), 150, OptionRight.CALL)
1414

1515

1616
# User generated method that gets called each time a message from the stream arrives.
1717
def callback(msg: StreamMsg):
1818
msg.type = msg.type
1919

2020
if msg.type == StreamMsgType.TRADE:
21-
print('con:' + msg.contract.to_string())
22-
print('trade: ' + msg.trade.to_string())
21+
print('---------------------------------------------------------------------------')
22+
print('con: ' + msg.contract.to_string())
23+
print('trade: ' + msg.trade.to_string())
24+
print('last quote at time of trade: ' + msg.quote.to_string())
2325

2426

2527
if __name__ == "__main__":

docs/options/trade_streaming_full.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ def streaming():
55
# Credentials now required because get_last is only available to ThetaData Standard & Pro subscribers.
66
client = ThetaClient(username="MyThetaDataEmail", passwd="MyThetaDataPassword")
77

8-
with client.connect_stream(callback):
9-
# requests every option trade
10-
client.req_full_trade_stream_opt()
8+
client.connect_stream(callback) # You can stop streaming by calling client.close_stream
9+
client.req_full_trade_stream_opt() # requests every option trade
1110

1211

1312
# User generated method that gets called each time a message from the stream arrives.
1413
def callback(msg: StreamMsg):
1514
msg.type = msg.type
1615

1716
if msg.type == StreamMsgType.TRADE:
18-
print('con:' + msg.contract.to_string())
19-
print('trade: ' + msg.trade.to_string())
17+
print('---------------------------------------------------------------------------')
18+
print('con: ' + msg.contract.to_string())
19+
print('trade: ' + msg.trade.to_string())
20+
print('last quote at time of trade: ' + msg.quote.to_string())
2021

2122

2223
if __name__ == "__main__":

docs/tutorials.md

+37-26
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,8 @@ existence and is able to have up to 15K quote streams. The Standard tier is only
259259

260260
### Option Trades
261261

262-
Below requests to receive continuous updates for trades for 4 NVDA option contracts. Notice
263-
that these options expire today, so you may need to change the expiration dates to a date
264-
further in the future.
262+
Below requests to receive continuous updates for trades for a NVDA option contract. Notice
263+
that these options are probably expired, so you may need to change the expiration date.
265264

266265
=== "trade_streaming.py"
267266

@@ -273,18 +272,23 @@ further in the future.
273272

274273
```bash
275274
> python trade_streaming.py
276-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 150.0 isCall: False
277-
trade: ms_of_day: 35319636 sequence: 1297770003 size: 1 condition: 18 price: 2.29 exchange: ARCX date: 2022-12-23
278-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 145.0 isCall: False
279-
trade: ms_of_day: 35319722 sequence: 1297772550 size: 1 condition: 18 price: 0.59 exchange: XBOS date: 2022-12-23
280-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 145.0 isCall: False
281-
trade: ms_of_day: 35320534 sequence: 1297793907 size: 1 condition: 18 price: 0.59 exchange: XISX date: 2022-12-23
282-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 145.0 isCall: False
283-
trade: ms_of_day: 35321269 sequence: 1297821400 size: 1 condition: 18 price: 0.6 exchange: ARCX date: 2022-12-23
284-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 145.0 isCall: False
285-
trade: ms_of_day: 35321269 sequence: 1297821467 size: 1 condition: 18 price: 0.6 exchange: EDGX date: 2022-12-23
286-
con:root: NVDA isOption: True exp: 2022-12-23 strike: 145.0 isCall: False
287-
trade: ms_of_day: 35321269 sequence: 1297821468 size: 1 condition: 18 price: 0.6 exchange: BATS date: 2022-12-23
275+
---------------------------------------------------------------------------
276+
con: root: MSFT isOption: True exp: 2023-06-16 strike: 185.0 isCall: False
277+
trade: ms_of_day: 54448612 sequence: 3464894509 size: 2 condition: AUTO_EXECUTION price: 4.95 exchange: date: 2022-12-27
278+
last quote at time of trade: ms_of_day: 54448612 bid_size: 2 bid_exchange: bid_price: 4.95 bid_condition: NATIONAL_BBO ask_size: 27 ask_exchange: XBOS ask_price: 5.05 ask_condition: NATIONAL_BBO date: 2022-12-27
279+
---------------------------------------------------------------------------
280+
con: root: MSFT isOption: True exp: 2023-06-16 strike: 185.0 isCall: False
281+
trade: ms_of_day: 54448614 sequence: 3464894620 size: 2 condition: INTERMARKET_SWEEP price: 4.95 exchange: date: 2022-12-27
282+
last quote at time of trade: ms_of_day: 54448613 bid_size: 1178 bid_exchange: bid_price: 4.95 bid_condition: NATIONAL_BBO ask_size: 27 ask_exchange: XBOS ask_price: 5.05 ask_condition: NATIONAL_BBO date: 2022-12-27
283+
---------------------------------------------------------------------------
284+
con: root: UUP isOption: True exp: 2023-01-27 strike: 28.5 isCall: True
285+
trade: ms_of_day: 46725445 sequence: 1876543798 size: 55 condition: AUTO_EXECUTION price: 0.23 exchange: date: 2022-12-27
286+
last quote at time of trade: ms_of_day: 46725445 bid_size: 1 bid_exchange: XNMS bid_price: 0.23 bid_condition: NATIONAL_BBO ask_size: 55 ask_exchange: ask_price: 0.23 ask_condition: NATIONAL_BBO date: 2022-12-27
287+
---------------------------------------------------------------------------
288+
con: root: UNM isOption: True exp: 2023-03-17 strike: 42.5 isCall: True
289+
trade: ms_of_day: 46725454 sequence: 1876544125 size: 1 condition: AUTO_EXECUTION price: 1.95 exchange: XNMS date: 2022-12-27
290+
last quote at time of trade: ms_of_day: 46725454 bid_size: 33 bid_exchange: XBOS bid_price: 1.85 bid_condition: NATIONAL_BBO ask_size: 2 ask_exchange: XMIO ask_price: 2.0 ask_condition: NATIONAL_BBO date: 2022-12-27
291+
---------------------------------------------------------------------------
288292
```
289293

290294
### Every Option Trade
@@ -302,16 +306,23 @@ available to PRO subscribers.
302306

303307
```bash
304308
> python trade_streaming_full.py
305-
con:root: SPXW isOption: True exp: 2023-01-06 strike: 3780.0 isCall: False
306-
trade: ms_of_day: 40566197 sequence: 81076302 size: 4 condition: 4294967170 price: 35.15 exchange: XCBO date: 2022-12-23
307-
con:root: CHWY isOption: True exp: 2023-01-20 strike: 42.5 isCall: False
308-
trade: ms_of_day: 57375126 sequence: 3619080181 size: 1 condition: 4294967178 price: 4.55 exchange: XMIO date: 2022-12-23
309-
con:root: TSLA isOption: True exp: 2022-12-23 strike: 132.0 isCall: True
310-
trade: ms_of_day: 40566210 sequence: 796495932 size: 6 condition: 18 price: 0.15 exchange: XCBO date: 2022-12-23
311-
con:root: TSLA isOption: True exp: 2022-12-23 strike: 132.0 isCall: True
312-
trade: ms_of_day: 40566210 sequence: 796495933 size: 6 condition: 18 price: 0.15 exchange: XCBO date: 2022-12-23
313-
con:root: SPY isOption: True exp: 2022-12-23 strike: 381.0 isCall: True
314-
trade: ms_of_day: 41027015 sequence: 716643310 size: 6 condition: 125 price: 1.07 exchange: EDGX date: 2022-12-23
309+
---------------------------------------------------------------------------
310+
con: root: SPY isOption: True exp: 2023-01-03 strike: 387.0 isCall: True
311+
trade: ms_of_day: 45506758 sequence: 2502262221 size: 23 condition: AUTO_EXECUTION price: 1.56 exchange: BATS date: 2022-12-27
312+
last quote at time of trade: ms_of_day: 45506758 bid_size: 159 bid_exchange: C2OX bid_price: 1.55 bid_condition: NATIONAL_BBO ask_size: 422 ask_exchange: MCRY ask_price: 1.57 ask_condition: NATIONAL_BBO date: 2022-12-27
313+
---------------------------------------------------------------------------
314+
con: root: NEE isOption: True exp: 2023-03-17 strike: 82.5 isCall: False
315+
trade: ms_of_day: 52558559 sequence: 3375727498 size: 1 condition: AUTO_EXECUTION price: 3.5 exchange: XCBO date: 2022-12-27
316+
last quote at time of trade: ms_of_day: 52558559 bid_size: 1266 bid_exchange: XPHL bid_price: 3.4 bid_condition: NATIONAL_BBO ask_size: 270 ask_exchange: XPHL ask_price: 3.6 ask_condition: NATIONAL_BBO date: 2022-12-27
317+
---------------------------------------------------------------------------
318+
con: root: TSLA isOption: True exp: 2023-01-27 strike: 95.0 isCall: False
319+
trade: ms_of_day: 46432515 sequence: 2064836636 size: 1 condition: AUTO_EXECUTION price: 5.15 exchange: ARCX date: 2022-12-27
320+
last quote at time of trade: ms_of_day: 46432515 bid_size: 852 bid_exchange: EDGX bid_price: 5.1 bid_condition: NATIONAL_BBO ask_size: 1 ask_exchange: ARCX ask_price: 5.15 ask_condition: NATIONAL_BBO date: 2022-12-27
321+
---------------------------------------------------------------------------
322+
con: root: USO isOption: True exp: 2023-01-06 strike: 80.0 isCall: False
323+
trade: ms_of_day: 46432592 sequence: 1863359037 size: 1 condition: SINGLE_LEG_AUCTION_NON_ISO price: 9.8 exchange: XMIO date: 2022-12-27
324+
last quote at time of trade: ms_of_day: 46429598 bid_size: 39 bid_exchange: XBOS bid_price: 9.55 bid_condition: NATIONAL_BBO ask_size: 39 ask_exchange: XBOS ask_price: 10.05 ask_condition: NATIONAL_BBO date: 2022-12-27
325+
---------------------------------------------------------------------------
315326
```
316327

317328
### Every Open Interest
@@ -328,7 +339,7 @@ available to PRO subscribers.
328339
=== "Output"
329340

330341
```bash
331-
> python trade_streaming_full.py
342+
> python open_interest_streaming.py
332343
con:root: ZROZ isOption: True exp: 2023-03-17 strike: 98.0 isCall: True open_interest: open_interest: 51 date: 2022-12-23
333344
con:root: XOM isOption: True exp: 2025-01-17 strike: 97.5 isCall: False open_interest: open_interest: 130 date: 2022-12-23
334345
con:root: XOP isOption: True exp: 2025-01-17 strike: 100.0 isCall: True open_interest: open_interest: 79 date: 2022-12-23

thetadata/client.py

+21-24
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def from_bytes(self, data: bytearray):
8686
def to_string(self) -> str:
8787
"""String representation of a trade."""
8888
return 'ms_of_day: ' + str(self.ms_of_day) + ' sequence: ' + str(self.sequence) + ' size: ' + str(self.size) + \
89-
' condition: ' + str(self.condition.name) + ' price: ' + str(self.price) + ' exchange: ' + \
89+
' condition: ' + str(self.condition.name) + ' price: ' + str(self.price) + ' exchange: ' + \
9090
str(self.exchange.value[1]) + ' date: ' + str(self.date)
9191

9292

@@ -222,6 +222,7 @@ def __init__(self, port: int = 11000, timeout: Optional[float] = 60, launch: boo
222222
self._server: Optional[socket.socket] = None # None while disconnected
223223
self._stream_server: Optional[socket.socket] = None # None while disconnected
224224
self.launch = launch
225+
self._stream_impl = None
225226

226227
if launch:
227228
if username == "default" or passwd == "default":
@@ -260,11 +261,8 @@ def connect(self):
260261
self._send_ver()
261262
yield
262263
finally:
263-
if self.launch:
264-
self.kill()
265264
self._server.close()
266265

267-
@contextmanager
268266
def connect_stream(self, callback):
269267
"""Initiate a connection with the Theta Terminal Stream server on `localhost`.
270268
Requests can only be made inside this generator aka the `with client.connect_stream()` block.
@@ -274,24 +272,23 @@ def connect_stream(self, callback):
274272
:raises ConnectionRefusedError: If the connection failed.
275273
:raises TimeoutError: If the timeout is set and has been reached.
276274
"""
277-
278-
try:
279-
for i in range(15):
280-
try:
281-
self._stream_server = socket.socket()
282-
self._stream_server.connect(("localhost", 10000))
283-
self._stream_server.settimeout(1)
284-
break
285-
except ConnectionError:
286-
if i == 14:
287-
raise ConnectionError('Unable to connect to the local Theta Terminal Stream process.'
288-
' Try restarting your system.')
289-
sleep(1)
290-
self._stream_server.settimeout(self.timeout)
291-
yield
292-
Thread(target=self._recv_stream(callback)).start()
293-
finally:
294-
self._stream_server.close()
275+
for i in range(15):
276+
try:
277+
self._stream_server = socket.socket()
278+
self._stream_server.connect(("localhost", 10000))
279+
self._stream_server.settimeout(1)
280+
break
281+
except ConnectionError:
282+
if i == 14:
283+
raise ConnectionError('Unable to connect to the local Theta Terminal Stream process. '
284+
'Try restarting your system.')
285+
sleep(1)
286+
self._stream_server.settimeout(self.timeout)
287+
self._stream_impl = callback
288+
Thread(target=self._recv_stream).start()
289+
290+
def close_stream(self):
291+
self._stream_server.close()
295292

296293
def req_full_trade_stream_opt(self):
297294
"""from_bytes
@@ -338,7 +335,7 @@ def req_quote_stream_opt(self, root: str, exp: date, strike: float, right: Optio
338335
f"&right={right.value}&sec={SecType.OPTION.value}&req={OptionReqType.QUOTE.value}\n"
339336
self._stream_server.sendall(hist_msg.encode("utf-8"))
340337

341-
def _recv_stream(self, callback):
338+
def _recv_stream(self):
342339
"""from_bytes
343340
"""
344341
msg = StreamMsg()
@@ -359,7 +356,7 @@ def _recv_stream(self, callback):
359356
msg.open_interest.from_bytes(data)
360357
else:
361358
continue
362-
callback(msg)
359+
self._stream_impl(msg)
363360

364361
def _read_stream(self, n_bytes: int) -> bytearray:
365362
"""from_bytes

thetadata/enums.py

+38-38
Original file line numberDiff line numberDiff line change
@@ -530,44 +530,44 @@ class TradeCondition(enum.Enum):
530530
TRADE_THRU_EXEMPT = 108
531531
IMPLIED = 109
532532
OTC = 110
533-
TBA_111 = 111
534-
TBA_112 = 112
535-
TBA_113 = 113
536-
TBA_114 = 114
537-
TBA_115 = 115
538-
TBA_116 = 116
539-
TBA_117 = 117
540-
TBA_118 = 118
541-
TBA_119 = 119
542-
TBA_120 = 120
543-
TBA_121 = 121
544-
TBA_122 = 122
545-
TBA_123 = 123
546-
TBA_124 = 124
547-
TBA_125 = 125
548-
TBA_126 = 126
549-
TBA_127 = 127
550-
TBA_128 = -128
551-
TBA_129 = -127
552-
TBA_130 = -126
553-
TBA_131 = -125
554-
TBA_132 = -124
555-
TBA_133 = -123
556-
TBA_134 = -122
557-
TBA_135 = -121
558-
TBA_136 = -120
559-
TBA_137 = -119
560-
TBA_138 = -118
561-
TBA_139 = -117
562-
TBA_140 = -116
563-
TBA_141 = -115
564-
TBA_142 = -114
565-
TBA_143 = -113
566-
TBA_144 = -112
567-
TBA_145 = -111
568-
TBA_146 = -110
569-
TBA_147 = -109
570-
TBA_148 = -108
533+
MKT_SUPERVISION = 111
534+
RESERVED_77 = 112
535+
RESERVED_91 = 113
536+
CONTINGENT_UTP = 114
537+
ODD_LOT = 115
538+
RESERVED_89 = 116
539+
CORRECTED_LAST = 117
540+
OPRA_EXT_HOURS = 118
541+
RESERVED_78 = 119
542+
RESERVED_81 = 120
543+
RESERVED_84 = 121
544+
RESERVED_878 = 122
545+
RESERVED_90 = 123
546+
QUALIFIED_CONTINGENT_TRADE = 124
547+
SINGLE_LEG_AUCTION_NON_ISO = 125
548+
SINGLE_LEG_AUCTION_ISO = 126
549+
SINGLE_LEG_CROSS_NON_ISO = 127
550+
SINGLE_LEG_CROSS_ISO = 128
551+
SINGLE_LEG_FLOOR_TRADE = 129
552+
MULTI_LEG_AUTO_ELECTRONIC_TRADE = 130
553+
MULTI_LEG_AUCTION = 131
554+
MULTI_LEG_CROSS = -132
555+
MULTI_LEG_FLOOR_TRADE = 133
556+
MULTI_LEG_AUTO_ELEC_TRADE_AGAINST_SINGLE_LEG = 134
557+
STOCK_OPTIONS_AUCTION = 135
558+
MULTI_LEG_AUCTION_AGAINST_SINGLE_LEG = 136
559+
MULTI_LEG_FLOOR_TRADE_AGAINST_SINGLE_LEG = 137
560+
STOCK_OPTIONS_AUTO_ELEC_TRADE = 138
561+
STOCK_OPTIONS_CROSS = 139
562+
STOCK_OPTIONS_FLOOR_TRADE = 140
563+
STOCK_OPTIONS_AUTO_ELEC_TRADE_AGAINST_SINGLE_LEG = 141
564+
STOCK_OPTIONS_AUCTION_AGAINST_SINGLE_LEG = 142
565+
STOCK_OPTIONS_FLOOR_TRADE_AGAINST_SINGLE_LEG = 143
566+
MULTI_LEG_FLOOR_TRADE_OF_PROPRIETARY_PRODUCTS = 144
567+
BID_AGGRESSOR = 145
568+
ASK_AGGRESSOR = 146
569+
MULTI_LATERAL_COMPRESSION_TRADE_OF_PROPRIETARY_DATA_PRODUCTS = 147
570+
EXTENDED_HOURS_TRADE = 148
571571
UNDEFINED = 10000
572572

573573
@classmethod

0 commit comments

Comments
 (0)