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