@@ -48,7 +48,7 @@ def __init__(self, *args, **kwargs):
48
48
elif not is_list_like (self .symbols ):
49
49
self .symbols = [self .symbols ]
50
50
51
- self .__engines , self . __markets = {}, {} # dicts for engines and markets
51
+ self .__markets_n_engines = {} # dicts for tuples of engines and markets
52
52
53
53
__url_metadata = "https://iss.moex.com/iss/securities/{symbol}.csv"
54
54
__url_data = (
@@ -60,17 +60,17 @@ def __init__(self, *args, **kwargs):
60
60
def url (self ):
61
61
"""Return a list of API URLs per symbol"""
62
62
63
- if not self .__engines or not self . __markets :
63
+ if not self .__markets_n_engines :
64
64
raise Exception (
65
65
"Accessing url property before invocation "
66
66
"of read() or _get_metadata() methods"
67
67
)
68
68
69
69
return [
70
70
self .__url_data .format (
71
- engine = self . __engines [ s ] , market = self . __markets [ s ] , symbol = s
72
- )
73
- for s in self .symbols
71
+ engine = engine , market = market , symbol = s
72
+ ) for s in self . symbols if s in self . __markets_n_engines
73
+ for market , engine in self .__markets_n_engines [ s ]
74
74
]
75
75
76
76
def _get_params (self , start ):
@@ -81,13 +81,13 @@ def _get_params(self, start):
81
81
"iss.dp" : "point" ,
82
82
"iss.df" : "%Y-%m-%d" ,
83
83
"iss.tf" : "%H:%M:%S" ,
84
- "iss.dft " : "%Y-%m-%d %H:%M:%S" ,
84
+ "iss.dtf " : "%Y-%m-%d %H:%M:%S" ,
85
85
"iss.json" : "extended" ,
86
86
"callback" : "JSON_CALLBACK" ,
87
87
"from" : start ,
88
88
"till" : self .end_dt .strftime ("%Y-%m-%d" ),
89
89
"limit" : 100 ,
90
- "start" : 1 ,
90
+ "start" : 0 ,
91
91
"sort_order" : "TRADEDATE" ,
92
92
"sort_order_desc" : "asc" ,
93
93
}
@@ -96,7 +96,7 @@ def _get_params(self, start):
96
96
def _get_metadata (self ):
97
97
"""Get markets and engines for the given symbols"""
98
98
99
- markets , engines = {}, {}
99
+ markets_n_engines = {}
100
100
101
101
for symbol in self .symbols :
102
102
response = self ._get_response (self .__url_metadata .format (symbol = symbol ))
@@ -118,9 +118,14 @@ def _get_metadata(self):
118
118
continue
119
119
if get_data and s != "" :
120
120
fields = s .split (";" )
121
- markets [symbol ], engines [symbol ] = fields [5 ], fields [7 ]
122
- break
123
- if symbol not in markets or symbol not in engines :
121
+
122
+ if symbol not in markets_n_engines :
123
+ markets_n_engines [symbol ] = list ()
124
+
125
+ markets_n_engines [symbol ].append (
126
+ (fields [5 ], fields [7 ])
127
+ ) # market and engine
128
+ if symbol not in markets_n_engines :
124
129
raise IOError (
125
130
"{} request returned no metadata: {}\n "
126
131
"Typo in the security symbol `{}`?" .format (
@@ -129,17 +134,20 @@ def _get_metadata(self):
129
134
symbol ,
130
135
)
131
136
)
132
- return markets , engines
137
+ if symbol in markets_n_engines :
138
+ markets_n_engines [symbol ] = list (set (markets_n_engines [symbol ]))
139
+ return markets_n_engines
133
140
134
141
def read (self ):
135
142
"""Read data"""
136
143
137
144
try :
138
- self .__markets , self .__engines = self ._get_metadata ()
145
+ self .__markets_n_engines = self ._get_metadata ()
146
+
139
147
urls = self .url # generate urls per symbols
140
148
dfs = [] # an array of pandas dataframes per symbol to concatenate
141
149
142
- for i in range (len (self . symbols )):
150
+ for i in range (len (urls )):
143
151
out_list = []
144
152
date_column = None
145
153
@@ -155,7 +163,7 @@ def read(self):
155
163
start_str = self .start .strftime ("%Y-%m-%d" )
156
164
start = self .start
157
165
158
- if start >= self .end or start >= dt .date .today ():
166
+ if start > self .end or start > dt .date .today ():
159
167
break
160
168
161
169
params = self ._get_params (start_str )
@@ -172,12 +180,19 @@ def read(self):
172
180
out_list += strings_out [1 :] # remove a CSV head line
173
181
if len (strings_out ) < 100 : # all data recevied - break
174
182
break
175
- str_io = StringIO ("\r \n " .join (out_list ))
176
- dfs .append (self ._read_lines (str_io )) # add a new DataFrame
183
+
184
+ if len (out_list ) > 0 :
185
+ str_io = StringIO ("\r \n " .join (out_list ))
186
+ dfs .append (self ._read_lines (str_io )) # add a new DataFrame
177
187
finally :
178
188
self .close ()
179
189
180
- if len (dfs ) > 1 :
190
+ if len (dfs ) == 0 :
191
+ raise IOError (
192
+ "{} returned no data; "
193
+ "check URL or correct a date" .format (self .__class__ .__name__ )
194
+ )
195
+ elif len (dfs ) > 1 :
181
196
return concat (dfs , axis = 0 , join = "outer" , sort = True )
182
197
else :
183
198
return dfs [0 ]
0 commit comments