1
1
"""Module that contains Theta Client class."""
2
2
import datetime
3
3
import threading
4
+ import time
4
5
import traceback
5
6
from decimal import Decimal
6
7
from threading import Thread
21
22
Header ,
22
23
TickBody ,
23
24
ListBody ,
24
- parse_list_REST , parse_hist_REST
25
+ parse_list_REST , parse_flexible_REST , parse_hist_REST , parse_hist_REST_stream , parse_hist_REST_stream_ijson ,
25
26
)
26
27
from .terminal import check_download , launch_terminal
27
28
28
29
_NOT_CONNECTED_MSG = "You must establish a connection first."
29
30
_VERSION = '0.9.0'
30
-
31
+ URL_BASE = "http://localhost:25510/"
31
32
32
33
def _format_strike (strike : float ) -> int :
33
34
"""Round USD to the nearest tenth of a cent, acceptable by the terminal."""
@@ -657,7 +658,6 @@ def get_hist_option_REST(
657
658
date_range : DateRange ,
658
659
interval_size : int = 0 ,
659
660
use_rth : bool = True ,
660
- progress_bar : bool = False ,
661
661
) -> pd .DataFrame :
662
662
"""
663
663
Get historical options data.
@@ -671,7 +671,6 @@ def get_hist_option_REST(
671
671
:param interval_size: The interval size in milliseconds. Applicable to most requests except ReqType.TRADE.
672
672
:param use_rth: If true, timestamps prior to 09:30 EST and after 16:00 EST will be ignored
673
673
(only applicable to intervals requests).
674
- :param progress_bar: Print a progress bar displaying download progress.
675
674
676
675
:return: The requested data as a pandas DataFrame.
677
676
:raises ResponseError: If the request failed.
@@ -683,13 +682,18 @@ def get_hist_option_REST(
683
682
start_fmt = _format_date (date_range .start )
684
683
end_fmt = _format_date (date_range .end )
685
684
right_fmt = right .value
686
-
685
+ use_rth_fmt = str ( use_rth ). lower ()
687
686
url = f"http://localhost:25510/hist/option/{ req_fmt } "
688
687
querystring = {"root" : root , "start_date" : start_fmt , "end_date" : end_fmt ,
689
688
"strike" : strike_fmt , "exp" : exp_fmt , "right" : right_fmt ,
690
- "ivl" : interval_size }
689
+ "ivl" : interval_size , "rth" : use_rth_fmt }
690
+ t1 = time .time ()
691
691
response = requests .get (url , params = querystring )
692
- df = parse_hist_REST (response , use_rth , progress_bar )
692
+ t2 = time .time ()
693
+ df = parse_flexible_REST (response )
694
+ t3 = time .time ()
695
+ print (f'time for request.get: { t2 - t1 } ' )
696
+ print (f'time for parse_flexible_REST(): { t3 - t2 } ' )
693
697
return df
694
698
695
699
def get_opt_at_time (
@@ -774,7 +778,7 @@ def get_opt_at_time_REST(
774
778
querystring = {"root" : root , "start_date" : start_fmt , "end_date" : end_fmt , "strike" : strike_fmt ,
775
779
"exp" : exp_fmt , "right" : right_fmt , "ivl" : ms_of_day }
776
780
response = requests .get (url , params = querystring )
777
- df = parse_hist_REST (response )
781
+ df = parse_flexible_REST (response )
778
782
return df
779
783
780
784
def get_stk_at_time (
@@ -842,8 +846,7 @@ def get_stk_at_time_REST(
842
846
querystring = {"root" : root_fmt , "start_date" : start_fmt ,
843
847
"end_date" : end_fmt , "ivl" : ms_of_day }
844
848
response = requests .get (url , params = querystring )
845
- print (response .url )
846
- df = parse_hist_REST (response )
849
+ df = parse_flexible_REST (response )
847
850
return df
848
851
849
852
def get_hist_stock (
@@ -894,7 +897,6 @@ def get_hist_stock_REST(
894
897
date_range : DateRange ,
895
898
interval_size : int = 0 ,
896
899
use_rth : bool = True ,
897
- progress_bar : bool = False ,
898
900
) -> pd .DataFrame :
899
901
"""
900
902
Get historical stock data.
@@ -904,7 +906,6 @@ def get_hist_stock_REST(
904
906
:param date_range: The dates to fetch.
905
907
:param interval_size: The interval size in milliseconds. Applicable only to OHLC & QUOTE requests.
906
908
:param use_rth: If true, timestamps prior to 09:30 EST and after 16:00 EST will be ignored.
907
- :param progress_bar: Print a progress bar displaying download progress.
908
909
909
910
:return: The requested data as a pandas DataFrame.
910
911
:raises ResponseError: If the request failed.
@@ -914,12 +915,12 @@ def get_hist_stock_REST(
914
915
req_fmt = req .name .lower ()
915
916
start_fmt = _format_date (date_range .start )
916
917
end_fmt = _format_date (date_range .end )
917
-
918
+ use_rth_fmt = str ( use_rth ). lower ()
918
919
url = f"http://localhost:25510/hist/stock/{ req_fmt } "
919
- querystring = {"root" : root , "start_date" : start_fmt , "end_date" : end_fmt ,
920
- "ivl" : interval_size }
921
- response = requests .get (url , params = querystring )
922
- df = parse_hist_REST (response , use_rth , progress_bar )
920
+ params = {"root" : root , "start_date" : start_fmt , "end_date" : end_fmt ,
921
+ "ivl" : interval_size , "rth" : use_rth_fmt }
922
+ response = requests .get (url , params = params )
923
+ df = parse_flexible_REST (response )
923
924
return df
924
925
925
926
# LISTING DATA
@@ -953,11 +954,13 @@ def get_dates_stk_REST(self, root: str, req: StockReqType) -> pd.Series:
953
954
:raises ResponseError: If the request failed.
954
955
:raises NoData: If there is no data available for the request.
955
956
"""
956
- url = "http://localhost:25510/list/dates/stock/quote"
957
- params = {'root' : root , 'req' : req }
957
+ root_fmt = root .lower ()
958
+ req_fmt = req .name .lower ()
959
+ url = f"http://localhost:25510/list/dates/stock/{ req_fmt } "
960
+ params = {'root' : root_fmt }
958
961
response = requests .get (url , params = params )
959
- df = parse_list_REST (response , dates = True )
960
- return df
962
+ series = parse_list_REST (response , dates = True )
963
+ return series
961
964
962
965
def get_dates_opt (
963
966
self ,
@@ -1015,7 +1018,6 @@ def get_dates_opt_REST(
1015
1018
sec = SecType .OPTION .value .lower ()
1016
1019
url = f"http://localhost:25510/list/dates/{ sec } /{ req } "
1017
1020
params = {'root' : root , 'exp' : exp_fmt , 'strike' : strike_fmt , 'right' : right }
1018
- # TODO: try using pd.read_json(url) to directly get dataframe from the URL
1019
1021
response = requests .get (url , params = params )
1020
1022
df = parse_list_REST (response , dates = True )
1021
1023
return df
@@ -1044,6 +1046,33 @@ def get_dates_opt_bulk(
1044
1046
body = ListBody .parse (out , header , self ._recv (header .size ), dates = True )
1045
1047
return body .lst
1046
1048
1049
+ def get_dates_opt_bulk_REST (
1050
+ self ,
1051
+ req : OptionReqType ,
1052
+ root : str ,
1053
+ exp : date ) -> pd .Series :
1054
+ """
1055
+ Get all dates of data available for a given options contract and request type.
1056
+
1057
+ :param req: The request type.
1058
+ :param root: The root / underlying / ticker / symbol.
1059
+ :param exp: The expiration date. Must be after the start of `date_range`.
1060
+ :param strike: The strike price in USD.
1061
+ :param right: The right of an options.
1062
+
1063
+ :return: All dates that Theta Data provides data for given a request.
1064
+ :raises ResponseError: If the request failed.
1065
+ :raises NoData: If there is no data available for the request.
1066
+ """
1067
+ req = req .name .lower ()
1068
+ exp_fmt = _format_date (exp )
1069
+ sec = SecType .OPTION .value .lower ()
1070
+ url = f"http://localhost:25510/list/dates/{ sec } /{ req } "
1071
+ params = {'root' : root , 'exp' : exp_fmt }
1072
+ response = requests .get (url , params = params )
1073
+ df = parse_list_REST (response , dates = True )
1074
+ return df
1075
+
1047
1076
def get_expirations (self , root : str ) -> pd .Series :
1048
1077
"""
1049
1078
Get all options expirations for a provided underlying root.
@@ -1168,14 +1197,10 @@ def get_roots_REST(self, sec: SecType) -> pd.Series:
1168
1197
:raises ResponseError: If the request failed.
1169
1198
:raises NoData: If there is no data available for the request.
1170
1199
"""
1171
- assert self ._server is not None , _NOT_CONNECTED_MSG
1172
1200
url = "http://localhost:25510/list/roots"
1173
- headers = {"Content-Type" : "application/json" }
1174
1201
params = {'sec' : sec .value }
1175
- #make call
1176
- raw_json = requests .get (url , params = params ).text
1177
- df = pd .read_json (raw_json , typ = "series" )
1178
- df = pd .Series (df ['response' ])
1202
+ response = requests .get (url , params = params )
1203
+ df = parse_list_REST (response )
1179
1204
return df
1180
1205
1181
1206
# LIVE DATA
0 commit comments