def get_a_quote_by_tdx(code_list): """ 获取A股市场行情,该接口只获取A股市场行情 其他的行情使用拓展行情接口 code_list:数字或者字符串格式的list,调用def standard_tdx_code(code_list)来格式化市场信息及code """ if len(code_list) == 0: return pd.DataFrame(columns=stock_tdx_columns) # 一次最多获取50只股票的实时行情,如果code_list 多于50只,则50只股票取一次行情,然后进行拼接 tdx_api = TdxHq_API() if len(code_list) >= 50: tmp = div_list(code_list, 50) df_tmp = pd.DataFrame(columns=stock_tdx_columns) if tdx_api.connect('119.147.212.81', 7709): for tmp_list in tmp: tmp_list = standard_tdx_code(tmp_list) tdx_data = tdx_api.to_df(tdx_api.get_security_quotes(tmp_list)) df_tmp = pd.concat([df_tmp, tdx_data]) df_tmp = df_tmp[stock_tdx_columns] else: tmp = standard_tdx_code(code_list) if tdx_api.connect('119.147.212.81', 7709): tdx_data = tdx_api.to_df(tdx_api.get_security_quotes(tmp)) df_tmp = tdx_data[stock_tdx_columns] tdx_api.disconnect() return process_tdx_price(df_tmp)
def quote_TDX(ds_tuple): api = TdxHq_API() if api.connect('119.147.212.81', 7709): MainCodeData = api.get_security_quotes([(1, code)]) n = ceil(len(ds_tuple) / 80) for i in range(n): if i == 0: quot = api.get_security_quotes(ds_tuple[i * 80:(i + 1) * 80]) #每次最多请求80个数据? else: quot_add = api.get_security_quotes( ds_tuple[i * 80:(i + 1) * 80]) quot = quot + quot_add api.disconnect() return quot, MainCodeData
def original_quotes(code, best_ip): api = TdxHq_API() api.connect(best_ip) now = datetime.now() data = [ api.get_security_quotes(code[80 * pos:80 * (pos + 1)]) for pos in range(int(len(code) / 80) + 1) ] return (datetime.now() - now).total_seconds()
def request_data(stklist, parse_one_result, ip, port): """请求失败将抛出异常""" api = TdxHq_API() hku_check(api.connect(ip, port), 'Failed connect tdx ({}:{})!'.format(ip, port)) quotes_list = api.get_security_quotes(stklist) result = [parse_one_result(q) for q in quotes_list] if quotes_list is not None else [] return [r for r in result if r is not None]
def original_quotes(): api = TdxHq_API() api.connect(best_ip) now = datetime.now() #data=api.get_security_quotes((get_market(x), x)) #print(data) data = [api.get_security_quotes([(get_market(x), x) for x in code[80 * pos:80 * (pos + 1)]]) for pos in range(int(len(code) / 80) + 1)] return data[0:-1]
def __hq_tick(self, code): api = TdxHq_API() ip, port = self.__hq.get() with api.connect(ip, port): df = api.get_security_quotes(code) if df is not None: df = api.to_df(df) api.disconnect() self.__hq.put((ip, port)) return df
def QA_fetch_get_stock_realtime(code=['000001', '000002'], ip=best_ip, port=7709): api = TdxHq_API() __data = pd.DataFrame() with api.connect(ip, port): code = [code] if type(code) is str else code for id_ in range(int(len(code) / 80) + 1): __data = __data.append(api.to_df(api.get_security_quotes( [(__select_market_code(x), x) for x in code[80 * id_:80 * (id_ + 1)]]))) __data['datetime'] = datetime.datetime.now() data = __data[['datetime', 'code', 'open', 'high', 'low', 'price']] return data.set_index('code', drop=False, inplace=False)
def get_up_count(webname='ths'): try: api = TdxHq_API() with api.connect('119.147.212.81', 7709): data = api.get_security_quotes([(1, '880005')]) this_count = data[0]['price'] return int(this_count) except Exception as e: headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' '(KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', } if webname == 'ths': try: #从同花顺取值 url = 'http://q.10jqka.com.cn/api.php?t=indexflash&' html = requests.get(url, headers=headers) jsoninfo = json.loads(html.text) this_count = jsoninfo['zdfb_data']['znum'] return this_count except Exception as e: #从东方财富取值 url = 'http://push2.eastmoney.com/api/qt/ulist.np/get?fid=f3&pi=0&pz=20&po=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&fields=f104&np=1&secids=1.000001,0.399001' html = requests.get(url, headers=headers) jsoninfo = json.loads(html.text) this_count = jsoninfo['data']['diff'][0]['f104'] + jsoninfo[ 'data']['diff'][1]['f104'] - 30 return this_count if webname == 'dfcf': try: #从东方财富取值 url = 'http://push2.eastmoney.com/api/qt/ulist.np/get?fid=f3&pi=0&pz=20&po=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&fields=f104&np=1&secids=1.000001,0.399001' html = requests.get(url, headers=headers) jsoninfo = json.loads(html.text) this_count = jsoninfo['data']['diff'][0]['f104'] + jsoninfo[ 'data']['diff'][1]['f104'] - 30 return this_count except Exception as e: #从同花顺取值 url = 'http://q.10jqka.com.cn/api.php?t=indexflash&' html = requests.get(url, headers=headers) jsoninfo = json.loads(html.text) this_count = jsoninfo['zdfb_data']['znum'] return this_count
def QA_fetch_depth_market_data(code=['000001', '000002'], ip=best_ip['stock'], port=7709): api = TdxHq_API() __data = pd.DataFrame() with api.connect(ip, port): code = [code] if type(code) is str else code for id_ in range(int(len(code) / 80) + 1): __data = __data.append(api.to_df(api.get_security_quotes( [(_select_market_code(x), x) for x in code[80 * id_:80 * (id_ + 1)]]))) __data['datetime'] = datetime.datetime.now() data = __data[['datetime', 'active1', 'active2', 'last_close', 'code', 'open', 'high', 'low', 'price', 'cur_vol', 's_vol', 'b_vol', 'vol', 'ask1', 'ask_vol1', 'bid1', 'bid_vol1', 'ask2', 'ask_vol2', 'bid2', 'bid_vol2', 'ask3', 'ask_vol3', 'bid3', 'bid_vol3', 'ask4', 'ask_vol4', 'bid4', 'bid_vol4', 'ask5', 'ask_vol5', 'bid5', 'bid_vol5']] return data.set_index(['datetime', 'code'], drop=False, inplace=False)
def get_quote_by_tdx(code_list): ''' 使用通达信接口获取股票实时行情 :param code_list: 股票代码list :return: df ''' tdx_code = stander_stock_code(code_list, 'tdx') if not tdx_code: return pd.DataFrame() api = TdxHq_API() with api.connect('119.147.212.81', 7709): data = api.to_df(api.get_security_quotes(tdx_code)) data = data[stock_tdx_columns] return data
def get_quote_by_tdx2(code_list, isbTDX): ''' 使用通达信接口获取股票实时行情 该方法带有市场信息,主要是对于一些ETF或者lof行情,不能用0开头还是6开头来判断是上海市场还是深圳市场 :param code_list: 股票代码list,带市场信息 :param isbTDX:true,带有通达信标准获取信息行情的内容 :return: df ''' if not isbTDX: return pd.DataFrame() api = TdxHq_API() with api.connect('119.147.212.81', 7709): data = api.to_df(api.get_security_quotes(code_list)) if data.empty: return pd.DataFrame() data = data[stock_tdx_columns] return data
def test_hq(): import pprint api = TdxHq_API(multithread=False) with api.connect(time_out=30): for i in range(100): stocks = api.get_security_quotes([(0, "000001"), (1, "600993")]) #print(stocks) #print(type(stocks)) print(stocks[1].get('code'), stocks[1].get('price'), stocks[1].get('bid1'), stocks[1].get('bid_vol1'), stocks[1].get('ask1'), stocks[1].get('ask_vol1')) #data = api.get_transaction_data(TDXParams.MARKET_SH, '601818', 0, 100) #pprint.pprint(data) #print('time:{},price:{},vol:{},buyorsell:{}'.format(data[0].get('time'), data[0].get('price'), data[0].get('vol'), data[0].get('buyorsell'))) time.sleep(1.5)
class PYTDXService(): """pytdx数据服务类""" def __init__(self): """Constructor""" self.connected = False # 数据服务连接状态 self.hq_api = None # 行情API def connect_api(self): """连接API""" # 连接增强行情API并检查连接情况 try: if not self.connected: host = SETTINGS["TDX_HOST"] port = SETTINGS["TDX_PORT"] self.hq_api = TdxHq_API() self.hq_api.connect(host, port) self.connected = True return True except Exception: raise ConnectionError("pytdx连接错误") def get_realtime_data(self, symbol: str): """获取股票实时数据""" try: symbols = self.generate_symbols(symbol) df = self.hq_api.to_df(self.hq_api.get_security_quotes(symbols)) return df except Exception: raise ValueError("股票数据获取失败") @staticmethod def generate_symbols(symbol: str): """组装symbols数据,pytdx接收的是以市场代码和标的代码组成的元祖的list""" new_symbols = [] code, exchange = symbol.split('.') new_symbols.append((exchange_map[exchange], code)) return new_symbols def close(self): """数据服务关闭""" self.connected = False self.hq_api.disconnect()
class tdxApi: def __init__(self): self.ipset = [(v[1], v[2]) for v in hq_hosts] random.shuffle(self.ipset) self.ippool = AvailableIPPool(TdxHq_API, self.ipset) self.primary_ip, _ = self.ippool.sync_get_top_n(2) self.api = TdxHq_API(multithread=True, heartbeat=True, auto_retry=True) def connect(self): self.api.connect(self.primary_ip[0], self.primary_ip[1]) def release(self): self.api.disconnect() def getQuotes(self, stock_list): datas = self.api.get_security_quotes(stock_list) if datas is None: return None else: return self.api.to_df(datas) def getList(self, market, index): df = self.api.to_df(self.api.get_security_list(market, index)) return df def getCount(self, market=0): return self.api.get_security_count(market) def getMinQuotes(self, market, stock_code): datas = self.api.get_minute_time_data(market, stock_code) if datas is None: return None return self.api.to_df(datas) def getMinQuotesHis(self, market, stock_code, date): datas = self.api.get_history_minute_time_data(market, stock_code, date) if datas is None: return None return self.api.to_df(datas)
def QA_fetch_depth_market_data(code=['000001', '000002'], ip=None, port=None): global best_ip if ip is None and port is None and best_ip['stock']['ip'] is None and best_ip['stock']['port'] is None: best_ip = select_best_ip() ip = best_ip['stock']['ip'] port = best_ip['stock']['port'] elif ip is None and port is None and best_ip['stock']['ip'] is not None and best_ip['stock']['port'] is not None: ip = best_ip['stock']['ip'] port = best_ip['stock']['port'] else: pass api = TdxHq_API() __data = pd.DataFrame() with api.connect(ip, port): code = [code] if type(code) is str else code for id_ in range(int(len(code) / 80) + 1): __data = __data.append(api.to_df(api.get_security_quotes( [(_select_market_code(x), x) for x in code[80 * id_:80 * (id_ + 1)]]))) __data['datetime'] = datetime.datetime.now() data = __data[['datetime', 'active1', 'active2', 'last_close', 'code', 'open', 'high', 'low', 'price', 'cur_vol', 's_vol', 'b_vol', 'vol', 'ask1', 'ask_vol1', 'bid1', 'bid_vol1', 'ask2', 'ask_vol2', 'bid2', 'bid_vol2', 'ask3', 'ask_vol3', 'bid3', 'bid_vol3', 'ask4', 'ask_vol4', 'bid4', 'bid_vol4', 'ask5', 'ask_vol5', 'bid5', 'bid_vol5']] return data.set_index(['datetime', 'code'], drop=False, inplace=False)
def QA_fetch_get_stock_realtime(code=['000001', '000002'], ip=None, port=None): global best_ip if ip is None and port is None and best_ip['stock']['ip'] is None and best_ip['stock']['port'] is None: best_ip = select_best_ip() ip = best_ip['stock']['ip'] port = best_ip['stock']['port'] elif ip is None and port is None and best_ip['stock']['ip'] is not None and best_ip['stock']['port'] is not None: ip = best_ip['stock']['ip'] port = best_ip['stock']['port'] else: pass api = TdxHq_API() __data = pd.DataFrame() with api.connect(ip, port): code = [code] if type(code) is str else code for id_ in range(int(len(code) / 80) + 1): __data = __data.append(api.to_df(api.get_security_quotes( [(_select_market_code(x), x) for x in code[80 * id_:80 * (id_ + 1)]]))) __data['datetime'] = datetime.datetime.now() data = __data[['datetime', 'active1', 'active2', 'last_close', 'code', 'open', 'high', 'low', 'price', 'cur_vol', 's_vol', 'b_vol', 'vol', 'ask1', 'ask_vol1', 'bid1', 'bid_vol1', 'ask2', 'ask_vol2', 'bid2', 'bid_vol2', 'ask3', 'ask_vol3', 'bid3', 'bid_vol3', 'ask4', 'ask_vol4', 'bid4', 'bid_vol4', 'ask5', 'ask_vol5', 'bid5', 'bid_vol5']] return data.set_index('code', drop=False, inplace=False)
def test_all_functions(multithread, heartbeat, auto_retry, raise_exception): api = TdxHq_API(multithread=multithread, heartbeat=heartbeat, auto_retry=auto_retry, raise_exception=raise_exception) with api.connect(time_out=30): log.info("获取股票行情") stocks = api.get_security_quotes([(0, "000001"), (1, "600300")]) assert stocks is not None assert type(stocks) is list # 方法2 stocks = api.get_security_quotes(0, "000001") assert stocks is not None assert type(stocks) is list # 方法3 stocks = api.get_security_quotes((0, "000001")) assert stocks is not None assert type(stocks) is list log.info("获取k线") data = api.get_security_bars(9, 0, '000001', 4, 3) assert data is not None assert type(data) is list assert len(data) == 3 log.info("获取 深市 股票数量") assert api.get_security_count(0) > 0 log.info("获取股票列表") stocks = api.get_security_list(1, 0) assert stocks is not None assert type(stocks) is list assert len(stocks) > 0 log.info("获取指数k线") data = api.get_index_bars(9, 1, '000001', 1, 2) assert data is not None assert type(data) is list assert len(data) == 2 log.info("查询分时行情") data = api.get_minute_time_data(TDXParams.MARKET_SH, '600300') assert data is not None log.info("查询历史分时行情") data = api.get_history_minute_time_data( TDXParams.MARKET_SH, '600300', 20161209) assert data is not None assert type(data) is list assert len(data) > 0 log.info("查询分时成交") data = api.get_transaction_data(TDXParams.MARKET_SZ, '000001', 0, 30) assert data is not None assert type(data) is list log.info("查询历史分时成交") data = api.get_history_transaction_data( TDXParams.MARKET_SZ, '000001', 0, 10, 20170209) assert data is not None assert type(data) is list assert len(data) == 10 log.info("查询公司信息目录") data = api.get_company_info_category(TDXParams.MARKET_SZ, '000001') assert data is not None assert type(data) is list assert len(data) > 0 start = data[0]['start'] length = data[0]['length'] log.info("读取公司信息-最新提示") data = api.get_company_info_content( 0, '000001', '000001.txt', start, length) assert data is not None assert len(data) > 0 log.info("读取除权除息信息") data = api.get_xdxr_info(1, '600300') assert data is not None assert type(data) is list assert len(data) > 0 log.info("读取财务信息") data = api.get_finance_info(0, '000001') assert data is not None assert type(data) is OrderedDict assert len(data) > 0 log.info("日线级别k线获取函数") data = api.get_k_data('000001', '2017-07-01', '2017-07-10') assert type(data) is pd.DataFrame assert len(data) == 6 log.info("获取板块信息") data = api.get_and_parse_block_info(TDXParams.BLOCK_FG) assert data is not None assert type(data) is list assert len(data) > 0
class TBStockData: __serverList = [] _bestIP = [] __bestIPFile = '' __tdx = None _lastBaseHistList = pd.DataFrame() _xdxrData = None def __init__(self, autoIP = False): self.__serverList = hq_hosts self.__bestIPFile = os.path.dirname(os.path.realpath(__file__)) + '/best.ip' if autoIP: self.getBestIP() else: if os.path.exists(self.__bestIPFile): with open(self.__bestIPFile, 'r') as f: data = f.read() self._bestIP = json.loads(data) def ping(self, ip, port): api = TdxHq_API() time1 = datetime.datetime.now() try: with api.connect(ip, int(port)): if len(api.get_security_list(0, 1)) > 800: return datetime.datetime.now() - time1 else: return datetime.timedelta(9, 9, 0) except: return datetime.timedelta(9, 9, 0) def getBestIP(self): pingTimeList = [self.ping(x[1], x[2]) for x in self.__serverList] self._bestIP = self.__serverList[pingTimeList.index(min(pingTimeList))] with open(self.__bestIPFile, 'w') as f: f.write(json.dumps(self._bestIP)) def showAllIP(self): for item in self.__serverList: print item[0],'\t', item[1], '\t', item[2] def _connect(self): if self.__tdx is None: if not self._bestIP: self.getBestIP() #self.__tdx = TdxHq_API(heartbeat=True, auto_retry=True) self.__tdx = TdxHq_API(auto_retry=True) self.__tdx.connect(self._bestIP[1], int(self._bestIP[2])) #计算量比 def _setVolRaito(self, row): date = row.name histList = self._lastBaseHistList[:date] if len(histList) < 6: return np.nan return round((histList['vol'].values[-1] / 240) / (histList[-6:-1]['vol'].sum() / 1200), 3) #计算各种指标 def getData(self, df = pd.DataFrame(), indexs=['turnover', 'vol', 'ma', 'macd', 'kdj', 'cci', 'bbi', 'sar', 'trix']): indexs = [x.lower() for x in indexs] histList = pd.DataFrame() if not df.empty: histList = df.copy() elif not self._lastBaseHistList.empty: histList = self._lastBaseHistList.copy() if histList.empty: return None dayKStatus = False try: if int(time.mktime(time.strptime(str(histList.index[-1]), "%Y-%m-%d %X"))) - int(time.mktime(time.strptime(str(histList.index[-2]), "%Y-%m-%d %X"))) > 43200: #日线以上行情 dayKStatus = True except: dayKStatus = True #计算涨幅 histList['p_change'] = histList['close'].pct_change().round(5) * 100 #量比 histList['vol_ratio'] = histList.apply(self._setVolRaito, axis=1) #振幅 histList['amp'] = ((histList['high'] - histList['low']) / histList.shift()['close'] * 100).round(3) #计算换手率 if self._xdxrData is None: xdxrData = self.getXdxr(str(histList['code'].values[0])) else: xdxrData = self._xdxrData info = xdxrData[xdxrData['liquidity_after'] > 0][['liquidity_after', 'shares_after']] if dayKStatus: startDate = str(histList.index[0])[0:10] endDate = str(histList.index[-1])[0:10] info1 = info[info.index <= startDate][-1:] info = info1.append(info[info.index >= startDate]).drop_duplicates() info = info.reindex(pd.date_range(info1.index[-1], endDate)) info = info.resample('1D').last().fillna(method='pad')[startDate:endDate] #info['date'] = info.index #info['date'] = info['date'].dt.strftime('%Y-%m-%d') #info = info.set_index('date') circulate = info['liquidity_after'] * 10000 capital = info['shares_after'] * 10000 else: circulate = info['liquidity_after'].values[-1] * 10000 capital = info['shares_after'].values[-1] * 10000 #histList['circulate'] = (circulate / 10000 / 10000).round(4) if 'turnover' in indexs and dayKStatus: histList['turnover'] = (histList['vol'] * 100 / circulate).round(5) * 100 histList['turnover5'] = talib.MA(histList['turnover'].values, timeperiod=5).round(3) #stockstats转换,主要是用来计算KDJ等相关指标 #用talib计算KDJ时会与现有软件偏差大 ss = StockDataFrame.retype(histList[['high','low','open','close']]) #MACD计算 if 'macd' in indexs: difList, deaList, macdList = talib.MACD(histList['close'].values, fastperiod=12, slowperiod=26, signalperiod=9) macdList = macdList * 2 histList['macd_dif'] = difList.round(3) histList['macd_dea'] = deaList.round(3) histList['macd_value'] = macdList.round(3) histList['macd_value_ma'] = 0 try: histList['macd_value_ma'] = talib.MA(histList['macd_value'].values, timeperiod=5).round(3) except: pass histList['macd_cross_status'] = 0 macdPosList = histList['macd_dif'] > histList['macd_dea'] histList.loc[macdPosList[(macdPosList == True) & (macdPosList.shift() == False)].index, 'macd_cross_status'] = 1 histList.loc[macdPosList[(macdPosList == False) & (macdPosList.shift() == True)].index, 'macd_cross_status'] = -1 #histList[['macd_cross_status']] = histList[['macd_cross_status']].fillna(method='pad') #KDJ计算 if 'kdj' in indexs: histList['kdj_k'] = ss['kdjk'].round(3) histList['kdj_d'] = ss['kdjd'].round(3) histList['kdj_j'] = ss['kdjj'].round(3) histList['kdj_cross_status'] = 0 kdjPosList = histList['kdj_k'] >= histList['kdj_d'] histList.loc[kdjPosList[(kdjPosList == True) & (kdjPosList.shift() == False)].index, 'kdj_cross_status'] = 1 histList.loc[kdjPosList[(kdjPosList == False) & (kdjPosList.shift() == True)].index, 'kdj_cross_status'] = -1 #histList[['kdj_cross_status']] = histList[['kdj_cross_status']].fillna(method='pad') #CCI计算 if 'cci' in indexs: histList['cci'] = ss['cci'].round(3) #ma相关计算 if 'ma' in indexs: histList['ma5'] = talib.MA(histList['close'].values, timeperiod=5).round(3) histList['ma10'] = talib.MA(histList['close'].values, timeperiod=10).round(3) histList['ma20'] = talib.MA(histList['close'].values, timeperiod=20).round(3) histList['ma30'] = talib.MA(histList['close'].values, timeperiod=30).round(3) histList['ma60'] = talib.MA(histList['close'].values, timeperiod=60).round(3) histList['ma240'] = talib.MA(histList['close'].values, timeperiod=240).round(3) histList[['ma5', 'ma10', 'ma20', 'ma30', 'ma60', 'ma240']] = histList[['ma5', 'ma10', 'ma20', 'ma30', 'ma60', 'ma240']].fillna(0) #成交量计算 if 'vol' in indexs: histList['vol5'] = talib.MA(histList['vol'].values, timeperiod=5).round(3) histList['vol10'] = talib.MA(histList['vol'].values, timeperiod=10).round(3) histList['vol20'] = talib.MA(histList['vol'].values, timeperiod=20).round(3) histList['vol_zoom'] = (histList['vol'] / histList['vol5'] * 1.0).round(3) histList['vol5_vol10_cross_status'] = 0 volumePosList = histList['vol5'] >= histList['vol10'] histList.loc[volumePosList[(volumePosList == True) & (volumePosList.shift() == False)].index, 'vol5_vol10_cross_status'] = 1 histList.loc[volumePosList[(volumePosList == False) & (volumePosList.shift() == True)].index, 'vol5_vol10_cross_status'] = -1 del volumePosList histList['vol5_vol20_cross_status'] = 0 volumePosList = histList['vol5'] >= histList['vol20'] histList.loc[volumePosList[(volumePosList == True) & (volumePosList.shift() == False)].index, 'vol5_vol20_cross_status'] = 1 histList.loc[volumePosList[(volumePosList == False) & (volumePosList.shift() == True)].index, 'vol5_vol20_cross_status'] = -1 del volumePosList histList['vol10_vol20_cross_status'] = 0 volumePosList = histList['vol10'] >= histList['vol20'] histList.loc[volumePosList[(volumePosList == True) & (volumePosList.shift() == False)].index, 'vol10_vol20_cross_status'] = 1 histList.loc[volumePosList[(volumePosList == False) & (volumePosList.shift() == True)].index, 'vol10_vol20_cross_status'] = -1 #histList[['vol5_vol10_cross_status', 'vol5_vol20_cross_status', 'vol10_vol20_cross_status']] = histList[['vol5_vol10_cross_status', 'vol5_vol20_cross_status', 'vol10_vol20_cross_status']].fillna(method='pad') #bbi计算 if 'bbi' in indexs: ma3 = talib.MA(histList['close'].values, timeperiod=3) ma6 = talib.MA(histList['close'].values, timeperiod=6) ma12 = talib.MA(histList['close'].values, timeperiod=12) ma24 = talib.MA(histList['close'].values, timeperiod=24) histList['bbi'] = (ma3 + ma6 + ma12 + ma24) / 4 histList['bbi'] = histList['bbi'].round(3) #SAR计算 if 'sar' in indexs: sarList = talib.SAR(histList['high'].values, histList['low'].values, acceleration=0.04, maximum=0.2) histList['sar'] = sarList.round(3) histList['sar_cross_status'] = 0 sarPosList = histList['close'] >= histList['sar'] histList.loc[sarPosList[(sarPosList == True) & (sarPosList.shift() == False)].index, 'sar_cross_status'] = 1 histList.loc[sarPosList[(sarPosList == False) & (sarPosList.shift() == True)].index, 'sar_cross_status'] = -1 #计算TRIX if 'trix' in indexs: histList['trix'] = np.nan histList['trma'] = np.nan histList['trix_diff'] = np.nan try: trix = talib.TRIX(histList['close'].values, 12) trma = talib.MA(trix, timeperiod=20) histList['trix'] = trix.round(3) histList['trma'] = trma.round(3) histList['trix_diff'] = histList['trix'] - histList['trma'] histList['trix_cross_status'] = 0 trixPosList = histList['trix'] >= histList['trma'] histList.loc[trixPosList[(trixPosList == True) & (trixPosList.shift() == False)].index, 'trix_cross_status'] = 1 histList.loc[trixPosList[(trixPosList == False) & (trixPosList.shift() == True)].index, 'trix_cross_status'] = -1 #histList[['trix_cross_status']] = histList[['trix_cross_status']].fillna(method='pad') except: pass if 'cyc' in indexs: avePrice = histList['amount'] / (histList['vol'] * 100) histList['cyc5'] = talib.MA(avePrice.values, timeperiod=5).round(3) histList['cyc13'] = talib.MA(avePrice.values, timeperiod=13).round(3) histList['cyc34'] = talib.MA(avePrice.values, timeperiod=34).round(3) #histList['cycx'] = talib.EMA(histList['close'].values, timeperiod=histList['vol'].values * 100 / circulate).round(3) histList['cyc5_cyc13_cross_status'] = 0 volumePosList = histList['cyc5'] >= histList['cyc13'] histList.loc[volumePosList[(volumePosList == True) & (volumePosList.shift() == False)].index, 'cyc5_cyc13_cross_status'] = 1 histList.loc[volumePosList[(volumePosList == False) & (volumePosList.shift() == True)].index, 'cyc5_cyc13_cross_status'] = -1 del volumePosList histList['cyc13_cyc34_cross_status'] = 0 volumePosList = histList['cyc13'] >= histList['cyc34'] histList.loc[volumePosList[(volumePosList == True) & (volumePosList.shift() == False)].index, 'cyc13_cyc34_cross_status'] = 1 histList.loc[volumePosList[(volumePosList == False) & (volumePosList.shift() == True)].index, 'cyc13_cyc34_cross_status'] = -1 del volumePosList if 'boll' in indexs: up, mid, low = talib.BBANDS( histList['close'].values, timeperiod=20, # number of non-biased standard deviations from the mean nbdevup=2, nbdevdn=2, # Moving average type: simple moving average here matype=0) histList['boll_up'] = up.round(3) histList['boll_mid'] = mid.round(3) histList['boll_low'] = low.round(3) return histList #整理开始,结束时间,并计算相差天数 def _getDate(self, start, end): if not end: end = time.strftime('%Y-%m-%d',time.localtime()) if not start: t = int(time.mktime(time.strptime(str(end), '%Y-%m-%d'))) - 86400 * 800 start = str(time.strftime('%Y-%m-%d',time.localtime(t))) startTimestamp = int(time.mktime(time.strptime(str(start), '%Y-%m-%d'))) endTimestamp = int(time.mktime(time.strptime(str(end), '%Y-%m-%d'))) diffDayNum = int((time.time() - startTimestamp) / 86400) if diffDayNum <= 0: diffDayNum = 1 return start, end, diffDayNum #得到市场代码 def getMarketCode(self, code): code = str(code) if code[0] in ['5', '6', '9'] or code[:3] in ["009", "126", "110", "201", "202", "203", "204"]: return 1 return 0 #时间整理 def _dateStamp(self, date): datestr = str(date)[0:10] date = time.mktime(time.strptime(datestr, '%Y-%m-%d')) return date #整理时间 def _timeStamp(self, _time): if len(str(_time)) == 10: # yyyy-mm-dd格式 return time.mktime(time.strptime(_time, '%Y-%m-%d')) elif len(str(_time)) == 16: # yyyy-mm-dd hh:mm格式 return time.mktime(time.strptime(_time, '%Y-%m-%d %H:%M')) else: timestr = str(_time)[0:19] return time.mktime(time.strptime(timestr, '%Y-%m-%d %H:%M:%S')) #得到除权信息 def getXdxr(self, code): self._connect() category = { '1': '除权除息', '2': '送配股上市', '3': '非流通股上市', '4': '未知股本变动', '5': '股本变化', '6': '增发新股', '7': '股份回购', '8': '增发新股上市', '9': '转配股上市', '10': '可转债上市', '11': '扩缩股', '12': '非流通股缩股', '13': '送认购权证', '14': '送认沽权证'} data = self.__tdx.to_df(self.__tdx.get_xdxr_info(self.getMarketCode(code), code)) if len(data) >= 1: data = data\ .assign(date=pd.to_datetime(data[['year', 'month', 'day']], format='%Y-%m-%d'))\ .drop(['year', 'month', 'day'], axis=1)\ .assign(category_meaning=data['category'].apply(lambda x: category[str(x)]))\ .assign(code=str(code))\ .rename(index=str, columns={'panhouliutong': 'liquidity_after', 'panqianliutong': 'liquidity_before', 'houzongguben': 'shares_after', 'qianzongguben': 'shares_before'})\ .set_index('date', drop=False, inplace=False) xdxrData = data.assign(date=data['date'].apply(lambda x: str(x)[0:10])) #xdxrData = xdxrData.set_index('date') self._xdxrData = xdxrData return xdxrData else: return None #得到股本 def getGuben(self, code): self._connect() if self._xdxrData is None: xdxrData = self.getXdxr(code) else: xdxrData = self._xdxrData info = xdxrData[xdxrData['liquidity_after'] > 0][['liquidity_after', 'shares_after']] circulate = info['liquidity_after'].values[-1] * 10000 capital = info['shares_after'].values[-1] * 10000 return capital,circulate #按天得到标准数据 ''' ktype = D(天)/W(周)/M(月)/Q(季)/Y(年) autype = bfq(不复权)/hfq(后复权)/qfq(前复权) ''' def getDays(self, code, ktype = 'D', start = '', end = '', autype = 'qfq', indexs = ['turnover', 'vol', 'ma', 'macd', 'kdj', 'cci', 'bbi', 'sar', 'trix']): startDate, endDate, diffDayNum = self._getDate(start, end) self._connect() ktypeCode = 9 if ktype.lower() == 'd': ktypeCode = 9 elif ktype.lower() == 'w': ktypeCode = 5 elif ktype.lower() == 'm': ktypeCode = 6 elif ktype.lower() == 'q': ktypeCode = 10 elif ktype.lower() == 'y': ktypeCode = 11 histList = pd.concat([self.__tdx.to_df(self.__tdx.get_security_bars(ktypeCode, self.getMarketCode(code), code, (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) if histList.empty: return None histList = histList[histList['open'] != 0] histList = histList[histList['vol'] > 1] if not autype or autype == 'bfq': histList = histList.assign(date=histList['datetime'].apply(lambda x: str(x[0:10]))).assign(code=str(code))\ .assign(date_stamp=histList['datetime'].apply(lambda x: self._dateStamp(str(x)[0:10]))) histList = histList.drop(['year', 'month', 'day', 'hour', 'minute', 'datetime', 'date_stamp'], axis=1) histList = histList.set_index('date') histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 if indexs: return self.getData(indexs=indexs) else: return histList elif autype == 'qfq': bfqData = histList.assign(date=pd.to_datetime(histList['datetime'].apply(lambda x: str(x[0:10])))).assign(code=str(code))\ .assign(date_stamp=histList['datetime'].apply(lambda x: self._dateStamp(str(x)[0:10]))) bfqData = bfqData.set_index('date') bfqData = bfqData.drop( ['year', 'month', 'day', 'hour', 'minute', 'datetime'], axis=1) xdxrData = self.getXdxr(code) if xdxrData is not None: info = xdxrData[xdxrData['category'] == 1] bfqData['if_trade'] = True data = pd.concat([bfqData, info[['category']] [bfqData.index[0]:]], axis=1) #data['date'] = data.index data['if_trade'].fillna(value=False, inplace=True) data = data.fillna(method='ffill') data = pd.concat([data, info[['fenhong', 'peigu', 'peigujia', 'songzhuangu']][bfqData.index[0]:]], axis=1) data = data.fillna(0) data['preclose'] = (data['close'].shift(1) * 10 - data['fenhong'] + data['peigu'] * data['peigujia']) / (10 + data['peigu'] + data['songzhuangu']) data['adj'] = (data['preclose'].shift(-1) / data['close']).fillna(1)[::-1].cumprod() data['open'] = data['open'] * data['adj'] data['high'] = data['high'] * data['adj'] data['low'] = data['low'] * data['adj'] data['close'] = data['close'] * data['adj'] data['preclose'] = data['preclose'] * data['adj'] data = data[data['if_trade']] histList = data.drop(['fenhong', 'peigu', 'peigujia', 'songzhuangu', 'if_trade', 'category', 'preclose', 'date_stamp', 'adj'], axis=1) histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 if indexs: return self.getData(indexs=indexs) else: return histList else: bfqData['preclose'] = bfqData['close'].shift(1) bfqData['adj'] = 1 histList = bfqData.drop(['preclose', 'date_stamp', 'adj'], axis=1) histList = histList[startDate:endDate] self._lastBaseHistList = histList if indexs: return self.getData(indexs=indexs) else: return histList elif autype == 'hfq': xdxrData = self.getXdxr(code) info = xdxrData[xdxrData['category'] == 1] bfqData = histList.assign(date=histList['datetime'].apply(lambda x: x[0:10])).assign(code=str(code))\ .assign(date_stamp=histList['datetime'].apply(lambda x: self._dateStamp(str(x)[0:10]))) bfqData = bfqData.set_index('date') bfqData = bfqData.drop( ['year', 'month', 'day', 'hour', 'minute', 'datetime'], axis=1) bfqData['if_trade'] = True data = pd.concat([bfqData, info[['category']] [bfqData.index[0]:]], axis=1) data['if_trade'].fillna(value=False, inplace=True) data = data.fillna(method='ffill') data = pd.concat([data, info[['fenhong', 'peigu', 'peigujia', 'songzhuangu']][bfqData.index[0]:]], axis=1) data = data.fillna(0) data['preclose'] = (data['close'].shift(1) * 10 - data['fenhong'] + data['peigu'] * data['peigujia']) / (10 + data['peigu'] + data['songzhuangu']) data['adj'] = (data['preclose'].shift(-1) / data['close']).fillna(1).cumprod() data['open'] = data['open'] / data['adj'] data['high'] = data['high'] / data['adj'] data['low'] = data['low'] / data['adj'] data['close'] = data['close'] / data['adj'] data['preclose'] = data['preclose'] / data['adj'] data = data[data['if_trade']] histList = data.drop(['fenhong', 'peigu', 'peigujia', 'songzhuangu', 'if_trade', 'category', 'preclose', 'date_stamp', 'adj'], axis=1) histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 if indexs: return self.getData(indexs=indexs) else: return histList #按分钟得到标准数据 ''' ktype = 1/5/15/30/60 分钟 ''' def getMins(self, code, ktype = 1, start = '', end = '', indexs=['vol', 'ma', 'macd', 'kdj', 'cci', 'bbi', 'sar', 'trix']): startDate, endDate, diffDayNum = self._getDate(start, end) self._connect() ktypeCode = 8 if int(ktype) == 1: ktypeCode = 8 diffDayNum = 240 * diffDayNum elif int(ktype) == 5: ktypeCode = 0 diffDayNum = 48 * diffDayNum elif int(ktype) == 15: ktypeCode = 1 diffDayNum = 16 * diffDayNum elif int(ktype) == 30: ktypeCode = 2 diffDayNum = 8 * diffDayNum elif int(ktype) == 60: ktypeCode = 3 diffDayNum = 4 * diffDayNum if diffDayNum > 20800: diffDayNum = 20800 histList = pd.concat([self.__tdx.to_df(self.__tdx.get_security_bars(ktypeCode, self.getMarketCode( str(code)), str(code), (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) if histList.empty: return None histList = histList\ .assign(datetime=pd.to_datetime(histList['datetime']), code=str(code))\ .assign(date=histList['datetime'].apply(lambda x: str(x)[0:10]))\ .assign(date_stamp=histList['datetime'].apply(lambda x: self._dateStamp(x)))\ .assign(time_stamp=histList['datetime'].apply(lambda x: self._timeStamp(x))) histList['date'] = histList['datetime'] histList = histList.drop(['year', 'month', 'day', 'hour', 'minute', 'datetime', 'date_stamp', 'time_stamp'], axis=1) histList = histList.set_index('date') histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 histList['vol'] = histList['vol'] / 100.0 if indexs: return self.getData(indexs=indexs) else: return histList #按天得到指数日k线 ''' ktype = D(天)/W(周)/M(月)/Q(季)/Y(年) ''' def getIndexDays(self, code, ktype = 'D', start = '', end = '', indexs=['turnover', 'vol', 'ma', 'macd', 'kdj', 'cci', 'bbi', 'sar', 'trix']): startDate, endDate, diffDayNum = self._getDate(start, end) self._connect() ktypeCode = 9 if ktype.lower() == 'd': ktypeCode = 9 elif ktype.lower() == 'w': ktypeCode = 5 elif ktype.lower() == 'm': ktypeCode = 6 elif ktype.lower() == 'q': ktypeCode = 10 elif ktype.lower() == 'y': ktypeCode = 11 if str(code)[0] in ['5', '1']: # ETF data = pd.concat([self.__tdx.to_df(self.__tdx.get_security_bars( ktypeCode, 1 if str(code)[0] in ['0', '8', '9', '5'] else 0, code, (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) else: data = pd.concat([self.__tdx.to_df(self.__tdx.get_index_bars( ktypeCode, 1 if str(code)[0] in ['0', '8', '9', '5'] else 0, code, (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) histList = data.assign(date=data['datetime'].apply(lambda x: str(x[0:10]))).assign(code=str(code))\ .assign(date_stamp=data['datetime'].apply(lambda x: self._dateStamp(str(x)[0:10])))\ .assign(code=code) if histList.empty: return None histList = histList.drop(['year', 'month', 'day', 'hour', 'minute', 'datetime', 'date_stamp', 'up_count', 'down_count'], axis=1) histList = histList.set_index('date') histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 if indexs: return self.getData(indexs=indexs) else: return histList #按分钟得到标准数据 ''' ktype = 1/5/15/30/60 分钟 ''' def getIndexMins(self, code, ktype = 1, start = '', end = '', indexs=['vol', 'ma', 'macd', 'kdj', 'cci', 'bbi', 'sar', 'trix']): startDate, endDate, diffDayNum = self._getDate(start, end) self._connect() ktypeCode = 8 if int(ktype) == 1: ktypeCode = 8 diffDayNum = 240 * diffDayNum elif int(ktype) == 5: ktypeCode = 0 diffDayNum = 48 * diffDayNum elif int(ktype) == 15: ktypeCode = 1 diffDayNum = 16 * diffDayNum elif int(ktype) == 30: ktypeCode = 2 diffDayNum = 8 * diffDayNum elif int(ktype) == 60: ktypeCode = 3 diffDayNum = 4 * diffDayNum if diffDayNum > 20800: diffDayNum = 20800 if str(code)[0] in ['5', '1']: # ETF data = pd.concat([self.__tdx.to_df(self.__tdx.get_security_bars( ktypeCode, 1 if str(code)[0] in ['0', '8', '9', '5'] else 0, code, (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) else: data = pd.concat([self.__tdx.to_df(self.__tdx.get_index_bars( ktypeCode, 1 if str(code)[0] in ['0', '8', '9', '5'] else 0, code, (int(diffDayNum / 800) - i) * 800, 800)) for i in range(int(diffDayNum / 800) + 1)], axis=0) histList = data.assign(datetime=pd.to_datetime(data['datetime']), code=str(code))\ .assign(date=data['datetime'].apply(lambda x: str(x)[0:10]))\ .assign(date_stamp=data['datetime'].apply(lambda x: self._dateStamp(x)))\ .assign(time_stamp=data['datetime'].apply(lambda x: self._timeStamp(x))) if histList.empty: return None histList['date'] = histList['datetime'] histList = histList.drop(['year', 'month', 'day', 'hour', 'minute', 'datetime', 'date_stamp', 'time_stamp', 'up_count', 'down_count'], axis=1) histList = histList.set_index('date') histList = histList[startDate:endDate] self._lastBaseHistList = histList histList['p_change'] = histList['close'].pct_change().round(5) * 100 if indexs: return self.getData(indexs=indexs) else: return histList #实时逐笔 ''' 0买 1卖 2中性 ''' def getRealtimeTransaction(self, code): self._connect() try: data = pd.concat([self.__tdx.to_df(self.__tdx.get_transaction_data( self.getMarketCode(str(code)), code, (2 - i) * 2000, 2000)) for i in range(3)], axis=0) if 'value' in data.columns: data = data.drop(['value'], axis=1) data = data.dropna() day = datetime.date.today() histList = data.assign(date=str(day)).assign(datetime=pd.to_datetime(data['time'].apply(lambda x: str(day) + ' ' + str(x))))\ .assign(code=str(code)).assign(order=range(len(data.index))) histList['money'] = histList['price'] * histList['vol'] * 100 histList['type'] = histList['buyorsell'] histList['type'].replace([0,1,2], ['B','S','N'], inplace = True) histList = histList.drop(['order', 'buyorsell'], axis=1).reset_index() return histList except: return None #历史逐笔 ''' 0买 1卖 2中性 ''' def getHistoryTransaction(self, code, date): self._connect() try: data = pd.concat([self.__tdx.to_df(self.__tdx.get_history_transaction_data( self.getMarketCode(str(code)), code, (2 - i) * 2000, 2000, int(str(date).replace('-', '')))) for i in range(3)], axis=0) if 'value' in data.columns: data = data.drop(['value'], axis=1) data = data.dropna() #day = datetime.date.today() day = date histList = data.assign(date=str(day)).assign(datetime=pd.to_datetime(data['time'].apply(lambda x: str(day) + ' ' + str(x))))\ .assign(code=str(code)).assign(order=range(len(data.index))) histList['money'] = histList['price'] * histList['vol'] * 100 histList['type'] = histList['buyorsell'] histList['type'].replace([0,1,2], ['B','S','N'], inplace = True) histList = histList.drop(['order', 'buyorsell'], axis=1).reset_index() return histList except: return None #实时分时数据 def getRealtimeMinuteTime(self, code): self._connect() date = str(time.strftime('%Y-%m-%d',time.localtime())) morningData = pd.date_range(start=str(date) + ' 09:31', end=str(date) + ' 11:30', freq = 'min') morningDF = pd.DataFrame(index=morningData) afternoonData = pd.date_range(start=str(date) + ' 13:01',end=str(date) + ' 15:00', freq = 'min') afternoonDF = pd.DataFrame(index=afternoonData) timeData = morningDF.append(afternoonDF) histList = self.__tdx.to_df(self.__tdx.get_minute_time_data( self.getMarketCode(str(code)), code)) #非标准均价计算 money = histList['price'] * histList['vol'] * 100 histList['money'] = money.round(2) totalMoney = money.cumsum() totalVol = histList['vol'].cumsum() histList['ave'] = totalMoney / (totalVol * 100) histList['ave'] = histList['ave'].round(3) histList['datetime'] = timeData.index[0:len(histList)] histList['date'] = histList['datetime'].apply(lambda x: x.strftime('%Y-%m-%d')) histList['time'] = histList['datetime'].apply(lambda x: x.strftime('%H:%M')) histList = histList.reset_index() return histList #历史分时数据 def getHistoryMinuteTime(self, code, date): self._connect() morningData = pd.date_range(start=str(date) + ' 09:31', end=str(date) + ' 11:30', freq = 'min') morningDF = pd.DataFrame(index=morningData) afternoonData = pd.date_range(start=str(date) + ' 13:01',end=str(date) + ' 15:00', freq = 'min') afternoonDF = pd.DataFrame(index=afternoonData) timeData = morningDF.append(afternoonDF) histList = self.__tdx.to_df(self.__tdx.get_history_minute_time_data( self.getMarketCode(str(code)), code, int(str(date).replace('-', '')))) #非标准均价计算 money = histList['price'] * histList['vol'] * 100 histList['money'] = money.round(2) totalMoney = money.cumsum() totalVol = histList['vol'].cumsum() histList['ave'] = totalMoney / (totalVol * 100) histList['ave'] = histList['ave'].round(3) histList['datetime'] = timeData.index[0:len(histList)] histList['date'] = histList['datetime'].apply(lambda x: x.strftime('%Y-%m-%d')) histList['time'] = histList['datetime'].apply(lambda x: x.strftime('%H:%M')) histList = histList.reset_index() return histList #实时报价(五档行情) ''' market => 市场 active1 => 活跃度 price => 现价 last_close => 昨收 open => 开盘 high => 最高 low => 最低 reversed_bytes0 => 保留 reversed_bytes1 => 保留 vol => 总量 cur_vol => 现量 amount => 总金额 s_vol => 内盘 b_vol => 外盘 reversed_bytes2 => 保留 reversed_bytes3 => 保留 bid1 => 买一价 ask1 => 卖一价 bid_vol1 => 买一量 ask_vol1 => 卖一量 bid2 => 买二价 ask2 => 卖二价 bid_vol2 => 买二量 ask_vol2 => 卖二量 bid3 => 买三价 ask3 => 卖三价 bid_vol3 => 买三量 ask_vol3 => 卖三量 bid4 => 买四价 ask4 => 卖四价 bid_vol4 => 买四量 ask_vol4 => 卖四量 bid5 => 买五价 ask5 => 卖五价 bid_vol5 => 买五量 ask_vol5 => 卖五量 reversed_bytes4 => 保留 reversed_bytes5 => 保留 reversed_bytes6 => 保留 reversed_bytes7 => 保留 reversed_bytes8 => 保留 reversed_bytes9 => 涨速 active2 => 活跃度 ''' def getRealtimeQuotes(self, codeList): self._connect() itemList = [] for item in codeList: itemList.append((self.getMarketCode(item), item)) histList = self.__tdx.to_df(self.__tdx.get_security_quotes(itemList)) histList = histList.set_index('code') return histList #计算指定日期成交量细节 def getVolAnalysis(self, code, date): self._connect() if str(time.strftime('%Y-%m-%d',time.localtime())) == str(date): if int(time.strftime('%H%M',time.localtime())) > 1600: volList = self.getHistoryTransaction(code, date) else: volList = self.getRealtimeTransaction(code) else: volList = self.getHistoryTransaction(code, date) if volList is None: return None guben,circulate = self.getGuben(code) if not self._lastBaseHistList.empty: histList = self._lastBaseHistList.copy() else: histList = self.getDays(code, end=date, indexs=[]) #涨停单数量 limitVol = round(histList[-5:]['vol'].mean() * 0.0618) #超大单,先转成市值,再转回成手数 superVol = float(circulate) * float(histList['close'].values[-1]) * 0.000618 / float(histList['close'].values[-1]) / 100 #大单 bigVol = round(superVol * 0.518) #中单 middleVol = round(superVol * 0.382) #小单 smallVol = round(superVol * 0.191) #买单统计 buyVolList = volList[volList['type'] == 'B'] totalBuyVolNum = buyVolList['vol'].sum() mainBuyVolNum = buyVolList[buyVolList['vol'] >= bigVol]['vol'].sum() limitBuyVolNum = math.ceil(buyVolList[(buyVolList['vol'] >= limitVol)]['vol'].sum() / limitVol) superBuyVolNum = math.ceil(buyVolList[(buyVolList['vol'] < limitVol) & (buyVolList['vol'] >= superVol)]['vol'].sum() / superVol) bigBuyVolNum = math.ceil(buyVolList[(buyVolList['vol'] < superVol) & (buyVolList['vol'] >= bigVol)]['vol'].sum() / bigVol) middleBuyVolNum = math.ceil(buyVolList[(buyVolList['vol'] < bigVol) & (buyVolList['vol'] >= middleVol)]['vol'].sum() / middleVol) smallBuyVolNum = math.ceil(buyVolList[(buyVolList['vol'] < middleVol) & (buyVolList['vol'] >= smallVol)]['vol'].sum() / smallVol) microBuyVolNum = len(buyVolList[(buyVolList['vol'] < smallVol)]) #print limitBuyVolNum,superBuyVolNum,bigBuyVolNum,middleBuyVolNum,smallBuyVolNum,microBuyVolNum #卖单统计 sellVolList = volList[volList['type'] == 'S'] totalSellVolNum = sellVolList['vol'].sum() mainSellVolNum = sellVolList[sellVolList['vol'] >= bigVol]['vol'].sum() limitSellVolNum = math.ceil(sellVolList[(sellVolList['vol'] >= limitVol)]['vol'].sum() / limitVol) superSellVolNum = math.ceil(sellVolList[(sellVolList['vol'] < limitVol) & (sellVolList['vol'] >= superVol)]['vol'].sum() / superVol) bigSellVolNum = math.ceil(sellVolList[(sellVolList['vol'] < superVol) & (sellVolList['vol'] >= bigVol)]['vol'].sum() / bigVol) middleSellVolNum = math.ceil(sellVolList[(sellVolList['vol'] < bigVol) & (sellVolList['vol'] >= middleVol)]['vol'].sum() / middleVol) smallSellVolNum = math.ceil(sellVolList[(sellVolList['vol'] < middleVol) & (sellVolList['vol'] >= smallVol)]['vol'].sum() / smallVol) microSellVolNum = len(sellVolList[(sellVolList['vol'] < smallVol)]) #print limitSellVolNum,superSellVolNum,bigSellVolNum,middleSellVolNum,smallSellVolNum,microSellVolNum #计算吸筹线 #主力标准吸筹金额 mainBaseMoney = round(histList['close'].values[-1] * circulate * 0.001 / 10000 / 10000, 4) #主力强力吸筹金额 mainBigMoney = round(histList['close'].values[-1] * circulate * 0.003 / 10000 / 10000, 4) #资金统计 totalMoney = round(volList['money'].sum() / 10000 / 10000, 4) totalBuyMoney = round(buyVolList['money'].sum() / 10000 / 10000, 4) totalSellMoney = round(sellVolList['money'].sum() / 10000 / 10000, 4) totalAbsMoney = round(totalBuyMoney - totalSellMoney, 3) mainMoney = round(volList[volList['vol'] >= bigVol]['money'].sum() / 10000 / 10000, 4) mainBuyMoney = round(buyVolList[buyVolList['vol'] >= bigVol]['money'].sum() / 10000 / 10000, 4) mainSellMoney = round(sellVolList[sellVolList['vol'] >= bigVol]['money'].sum() / 10000 / 10000, 4) mainAbsMoney = round(mainBuyMoney - mainSellMoney, 3) mainRate = 0 try: mainRate = round((mainBuyMoney + mainSellMoney) / totalMoney * 100, 2) except: pass mainBuyRate = 0 try: mainBuyRate = round(mainBuyMoney / (mainBuyMoney + mainSellMoney) * 100, 2) except: pass #print totalAbsMoney,mainAbsMoney,totalMoney,totalBuyMoney,totalSellMoney,mainBuyMoney,mainSellMoney,mainRate,mainBuyRate #成交笔数 volNum = len(volList) #平均每笔交易价格 aveTradePrice = round(totalMoney / volNum * 10000 * 10000, 2) #平均每股买价格 avePerShareBuyPrice = 0 try: avePerShareBuyPrice = round(totalBuyMoney * 10000 * 10000 / (totalBuyVolNum * 100), 3) except: pass #主力平均每股买价格 mainAvePerShareBuyPrice = 0 try: mainAvePerShareBuyPrice = round(mainBuyMoney * 10000 * 10000 / (mainBuyVolNum * 100), 3) except: pass #平均每股卖价格 avePerShareSellPrice = 0 try: avePerShareSellPrice = round(totalSellMoney * 10000 * 10000 / (totalSellVolNum * 100), 3) except: pass #主力平均每股卖价格 mainAvePerShareSellPrice = 0 try: mainAvePerShareSellPrice = round(mainSellMoney * 10000 * 10000 / (mainSellVolNum * 100), 3) except: pass #print totalMoney,volNum,aveVolPrice * 10000 * 10000 statData = {} statData['limit_buy_vol_num'] = limitBuyVolNum statData['super_buy_vol_num'] = superBuyVolNum statData['big_buy_vol_num'] = bigBuyVolNum statData['middle_buy_vol_num'] = middleBuyVolNum statData['small_buy_vol_num'] = smallBuyVolNum statData['micro_buy_vol_num'] = microBuyVolNum statData['limit_sell_vol_num'] = limitSellVolNum statData['super_sell_vol_num'] = superSellVolNum statData['big_sell_vol_num'] = bigSellVolNum statData['middle_sell_vol_num'] = middleSellVolNum statData['small_sell_vol_num'] = smallSellVolNum statData['micro_sell_vol_num'] = microSellVolNum statData['total_abs_money'] = totalAbsMoney statData['main_abs_money'] = mainAbsMoney statData['total_money'] = totalMoney statData['total_buy_money'] = totalBuyMoney statData['total_sell_money'] = totalSellMoney statData['main_money'] = mainMoney statData['main_buy_money'] = mainBuyMoney statData['main_sell_money'] = mainSellMoney statData['main_rate'] = mainRate statData['main_buy_rate'] = mainBuyRate statData['trade_num'] = volNum statData['vol_num'] = volList['vol'].sum() statData['ave_trade_price'] = aveTradePrice statData['main_base_money'] = mainBaseMoney statData['main_big_money'] = mainBigMoney statData['ave_per_share_buy_price'] = avePerShareBuyPrice statData['ave_per_share_sell_price'] = avePerShareSellPrice statData['main_ave_per_share_buy_price'] = mainAvePerShareBuyPrice statData['main_ave_per_share_sell_price'] = mainAvePerShareSellPrice statData['circulate_money'] = round(circulate * histList['close'].values[-1] / 10000 / 10000, 4) return statData #输出ebk文件 def outputEbk(self, stockList, ebkPath = ''): if len(ebkPath) <= 0: ebkPath = os.getcwd() + '/' + sys.argv[0][0:-3] + '.' + str(time.strftime('%Y%m%d',time.localtime())) + '.ebk' if not isinstance(stockList,list): return False fp = open(ebkPath, "a") fp.write('\r\n') #ebk第一行为空行 for code in stockList: if self.getMarketCode(code) == 1: fp.write('1' + code) else: fp.write('0' + code) fp.write('\r\n') fp.close() return True #输出sel文件 def outputSel(self, stockList, selPath = ''): import struct if len(selPath) <= 0: selPath = os.getcwd() + '/' + sys.argv[0][0:-3] + '.' + str(time.strftime('%Y%m%d',time.localtime())) + '.sel' if not isinstance(stockList,list): return False stocks = [] for code in stockList: if self.getMarketCode(code) == 1: stocks.append('\x07\x11' + code) else: stocks.append('\x07\x21' + code) with open(selPath, 'ab') as fp: data = struct.pack('H', len(stocks)).decode() + ''.join(stocks) fp.write(data.encode()) return True #ebk to sel def ebk2sel(self, ebkPath): import struct if not os.path.exists(ebkPath): return False selPath = ebkPath.replace('.ebk', '.sel') stocks = [] with open(ebkPath, 'r') as ebkfp: for code in ebkfp: code = code.strip() if len(code) > 0: if self.getMarketCode(code[1:]) == 1: stocks.append('\x07\x11' + code[1:]) else: stocks.append('\x07\x21' + code[1:]) with open(selPath, 'wb') as selfp: data = struct.pack('H', len(stocks)).decode() + ''.join(stocks) selfp.write(data.encode()) return True #sel to ebk def sel2ebk(self, selPath): import struct if not os.path.exists(selPath): return False ebkPath = selPath.replace('.sel', '.ebk') with open(selPath, 'rb') as selfp: ebkfp = open(ebkPath, "a") cnt = struct.unpack('<H', selfp.read(2))[0] for _ in range(cnt): data = selfp.readline(8).decode() exch = '1' if data[1] == '\x11' else '0' code = exch + data[2:] ebkfp.write(code + '\r\n') ebkfp.close() return True
from pytdx.hq import TdxHq_API api = TdxHq_API() with api.connect('119.147.212.81', 7709): df = api.to_df(api.get_security_quotes([(0, '000001'), (1, '600300')])) print(df.to_json()) data = api.get_minute_time_data(1, '600300') print(data) list_df = api.to_df(api.get_security_list(0, 300)) print(list_df.to_json())
class MongoDB(object): def __init__( self, ip="stock_mongo", #mongo db 数据库docker 容器名 port=27017, user_name=None, pwd=None, authdb=None): self.__server_ip = ip self.__server_port = port self.__user_name = user_name self.__pwd = pwd self.__authdb = authdb self.client = None self.trade_day = True self.TDX_IP_SETS = STOCK_IP_SETS self.api = TdxHq_API(heartbeat=True) self.today = None self.accounts = [] self.db = "stock_mock" #数据库 self.account_collection = "account" #保存各个账户的当前资金信息 self.account_his_collection = "account_history" #保存每个账户的历史净值信息 self.prefix = "holdlist_" self.accounts = [] self.stocks = [] def connect(self): '''建立数据库的连接 ''' _db_session = MongoClient(self.__server_ip, self.__server_port) if self.__user_name: eval("_db_session.{}".format(self.__authdb)).authenticate( self.__user_name, self.__pwd) self.client = _db_session def connect_market(self): for ip in self.TDX_IP_SETS: try: if self.api.connect(ip, 7709): return except: pass def disconnect(self): '''断开数据库连接 ''' self.client.close() return True def _dbclient(self, db): '''返回某个特定数据库的对象 ''' return eval("self.client.{}".format(db)) def handle_ex_right(self): '''处理持仓股票除权价格和数量 ''' func = lambda x: 0 if not x else x today = datetime.datetime.today().date().day year = datetime.datetime.today().date().year month = datetime.datetime.today().date().month for stock in self.stocks: mk = self._select_market_code(stock) cqcx = self.api.get_xdxr_info(mk, stock)[::-1] dct = {"fenhong": 0, 'peigu': 0, 'peigujia': 0, "songzhuangu": 0} iscq = False for i in cqcx: if i["day"] != today or i["month"] != month or i[ "year"] != year: break else: iscq = True dct["fenhong"] += func(i["fenhong"]) dct["peigu"] += func(i["peigu"]) dct["peigujia"] += func(i["peigujia"]) dct["songzhuangu"] += func(i["songzhuangu"]) if iscq: #发生除权除息 rst = self.api.get_security_bars(4, mk, stock, 0, 2) if rst[0]["day"] != today or i["month"] != month or i[ "year"] != year: close = rst[0]["close"] else: close = rst[1]["close"] preclose = (close * 10 - dct["fenhong"] + dct["peigu"] * dct['peigujia']) / ( 10 + dct['peigu'] + dct['songzhuangu']) rate = close / preclose logger.info("除权除息:{},rate:{}".format(stock, rate)) for account in self.accounts: filt = {"code": stock, "cx_date": {"$ne": self.today}} dt = { "$mul": { "cost": 1 / rate, "number": rate }, "$set": { "cx_date": self.today } } self._dbclient(self.db)[self.prefix + account].update_one( filt, dt) def set_accounts(self): self.accounts = [ i["account"] for i in self._dbclient(self.db)[self.account_collection].find() ] def set_stocks(self): rst = [] for account in self.accounts: rst.extend([ i["code"] for i in self._dbclient(self.db)[self.prefix + account].find( {"number": { "$gt": 0 }}, { "_id": 0, "code": 1 }) ]) self.stocks = set(rst) def initial(self): '''每天初始化状态,连接行情数据源,更新除权信息 ''' self.today = datetime.datetime.today().date().strftime('%Y-%m-%d') df = ts.trade_cal() self.trade_day = df[( df["calendarDate"] == self.today)].isOpen.values[0] if self.trade_day: #交易日,连接数据库,连接行情源,处理除权除息 self.connect() self.connect_market() self.set_accounts() self.set_stocks() self.handle_ex_right() logger.info("initial finished") def _select_market_code(self, code): code = str(code) if code[0] in ['5', '6', '9'] or code[:3] in [ "009", "126", "110", "201", "202", "203", "204" ]: return 1 return 0 def updateaccount(self, account="test"): '''更新账户净值,添加一条净值记录 ''' hold_collection = self.prefix + account tm = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") plimit = 80 filt = {'number': {'$gt': 0}} stocks = [(self._select_market_code(i["code"]), i["code"]) for i in self._dbclient(self.db)[hold_collection].find(filt)] rst = {} for i in range(math.ceil(len(stocks) / plimit)): ss = stocks[i * plimit:(i + 1) * plimit] for item in self.api.get_security_quotes(ss): rst[item["code"]] = item["price"] if len(rst) > 0: bulk = self._dbclient( self.db)[hold_collection].initialize_ordered_bulk_op() for code, price in rst.items(): d = {"price": price, "update_datetime": tm} bulk.find({"code": code}).upsert().update({"$set": d}) bulk.execute() holdvalue = self._dbclient(self.db)[hold_collection].aggregate([{ "$group": { "_id": None, "total": { "$sum": { "$multiply": ["$price", "$number"] } } } }]) try: holdvalue = [i for i in holdvalue][0]["total"] except: holdvalue = 0 rst = self._dbclient(self.db)[self.account_collection].find( {"account": account}, {"_id": 0})[0] rst["total"] = rst["rest"] + holdvalue rst["hold"] = holdvalue #更新账户当前值 self._dbclient(self.db)[self.account_collection].update_one( {"account": account}, {"$set": rst}) #更新账户历史记录值 dtm = datetime.datetime.now() minute = dtm.minute if minute >= 50: dtm = dtm.replace(hour=dtm.hour + 1, minute=0) else: minute = int(minute / 10) * 10 + 10 dtm = dtm.replace(minute=minute) self._dbclient(self.db)[self.account_his_collection].update_one( { "account": account, "date": dtm.strftime("%Y-%m-%d %H:%M") }, {"$set": rst}, upsert=True) def run(self): if not self.trade_day: #交易日,更新账户信息 return for account in self.accounts: self.updateaccount(account)
def single_client_benchmark(ip): def _log(msg): click.echo("HQ_BENCHMARK: [{:15s}] {} ".format(ip, datetime.datetime.now()) + msg) def _grouped_list(stocks): return [stocks[i:i + GET_QUOTES_PER_GROUPS] for i in range(0, len(stocks), GET_QUOTES_PER_GROUPS)] _log("start benchmark") total_time = connecting_time = get_security_count_time = get_security_list_time = get_security_quotes_time = num = 0 start_time = time.time() last_time = start_time try: api = TdxHq_API(multithread=True) port = 7709 if ":" in ip: ip, port = ip.split(':') port = int(port) with api.connect(ip=ip, port=port): _log("connected") cur_time = time.time() connecting_time = cur_time - last_time last_time = cur_time _log("connecting time is {}".format(connecting_time)) num = api.get_security_count(0) _log("all shenzhen market stock count is {}".format(num)) cur_time = time.time() get_security_count_time = cur_time - last_time last_time = cur_time _log("get_security_count_time is {}".format(get_security_count_time)) all = [] for i in range((num // 1000) + 1): offset = i * 1000 section = api.get_security_list(0, offset) all = all + section cur_time = time.time() get_security_list_time = cur_time - last_time last_time = cur_time _log("get_security_list_time is {}".format(get_security_list_time)) codes = [one['code'] for one in all] results = [] for stocks in _grouped_list(codes): req_list = [(0, code) for code in stocks] one_results = api.get_security_quotes(req_list) results = results + one_results cur_time = time.time() get_security_quotes_time = cur_time - last_time last_time = cur_time _log("get_security_quotes_time is {}".format(get_security_quotes_time)) total_time = last_time - start_time _log("total_time is {}".format(total_time)) _log("end benchmark") except Exception as e: _log("hit exception " + str(e)) return { "ip": ip, "total_time": total_time, "connecting_time": connecting_time, "get_security_count_time": get_security_count_time, "get_security_list_time": get_security_list_time, "get_security_quotes_time": get_security_quotes_time, "security_count": num }
class TDX_GW(object): __lc_min_bar_reader = None __daily_bar_reader = None __tdx_api = None __connected_ip = '119.147.212.81' __connected_port = 7709 def __init__(self): self.__lc_min_bar_reader = lc_min_bar_reader.TdxLCMinBarReader() self.__daily_bar_reader = TdxDailyBarReader() self.__block_reader = block_reader.BlockReader() self.__tdx_api = TdxHq_API() self.__cfg_provider = ConfigProvider.ConfigProvider() def get_local_stock_bars(self, file_path: str, stock_date_type: StockDataType): if stock_date_type == StockDataType.ONE_MIN or \ stock_date_type == StockDataType.FIVE_MINS: # start = time.time() # df = self.__lc_min_bar_reader.get_df(file_path) data = self.__lc_min_bar_reader.parse_data_by_file(file_path) df = pd.DataFrame(data=data) # df = df['date', 'open', 'high', 'low', 'close', 'amount', 'volume'] # print(f"TDX get 1min bar time spent: {(time.time() - start) * 1000} ms") return df[['date', 'open', 'high', 'low', 'close', 'amount', 'volume']] elif stock_date_type == StockDataType.DAILY: data = self.__daily_bar_reader.get_df(file_path).reset_index() data['date'] = data['date'].dt.strftime('%Y-%m-%d') return data[['date', 'open', 'high', 'low', 'close', 'amount', 'volume']] else: raise UnimplementedException def get_local_stock_bars_raw_data(self, file_path: str, stock_date_type: StockDataType): if stock_date_type == StockDataType.ONE_MIN or \ stock_date_type == StockDataType.FIVE_MINS: return self.__lc_min_bar_reader.parse_data_by_file(file_path) elif stock_date_type == StockDataType.DAILY: return self.__daily_bar_reader.parse_data_by_file(file_path) else: raise UnimplementedException def get_local_block(self): file_path = self.__cfg_provider.get_tdx_block_directory_path() return self.__block_reader.get_df(file_path, BlockReader_TYPE_GROUP) def get_realtime_stock_1min_bars(self, market: str, stock_id: str): with self.__tdx_api.connect(self.__connected_ip, self.__connected_port): market_code = self.__get_market_code(market) df = self.__tdx_api.to_df( self.__tdx_api.get_security_bars(8, market_code, stock_id, 0, 10)) # 返回DataFrame return df def get_realtime_stocks_quotes(self, stock_ids: []): stock_list = [] for id in stock_ids: stock_list.append((com_utils.get_stock_market(id), id)) with self.__tdx_api.connect(self.__connected_ip, self.__connected_port): return self.__tdx_api.get_security_quotes(stock_list) def get_history_minute_time_data(self, market: str, stock_id: str, date: int): with self.__tdx_api.connect(self.__connected_ip, self.__connected_port): market_code = self.__get_market_code(market) df = self.__tdx_api.to_df( self.__tdx_api.get_history_minute_time_data(market_code, stock_id, date)) return df def get_xdxr_info(self, market: str, stock_id: str): with self.__tdx_api.connect(self.__connected_ip, self.__connected_port): market_code = self.__get_market_code(market) df = self.__tdx_api.to_df( self.__tdx_api.get_xdxr_info(market_code, stock_id)) return df def test(self): with self.__tdx_api.connect(self.__connected_ip, self.__connected_port): return self.__tdx_api.get_history_minute_time_data(0, '000001', '2019-05-05') def __get_market_code(self, market: str): if market == cfg.MARKET.SHANGHAI: return 1 elif market == cfg.MARKET.SHENZHEN: return 0 else: raise UnimplementedException
def get_all_stock(): df = ts.get_stock_basics() df['stock'] = df.index df = df.sort_values(by=['stock'], ascending=True) df['stock'] = df.stock.map(lambda x: (1 if str(x).startswith('60') else 0, x)) return df['stock'].tolist() if __name__ == '__main__': stocks = get_all_stock() api = TdxHq_API() if api.connect('119.147.212.81', 7709): data = api.get_security_quotes(stocks[0:200]) print(data) api.disconnect() # ips = [(v[1], v[2]) for v in hq_hosts] # # 获取5个随机ip作为ip池 # random.shuffle(ips) # ips5 = ips[:5] # # ## IP 池对象 # ippool = AvailableIPPool(TdxHq_API, ips5) # # ## 选出M, H # primary_ip, hot_backup_ip = ippool.sync_get_top_n(2) # # print("make pool api")
("bid4", self._cal_price(price, bid4)), ("ask4", self._cal_price(price, ask4)), ("bid_vol4", bid_vol4), ("ask_vol4", ask_vol4), ("bid5", self._cal_price(price, bid5)), ("ask5", self._cal_price(price, ask5)), ("bid_vol5", bid_vol5), ("ask_vol5", ask_vol5), ("reversed_bytes4", reversed_bytes4), ("reversed_bytes5", reversed_bytes5), ("reversed_bytes6", reversed_bytes6), ("reversed_bytes7", reversed_bytes7), ("reversed_bytes8", reversed_bytes8), ("reversed_bytes9", reversed_bytes9 / 100.0), # 涨速 ("active2", active2) ]) stocks.append(one_stock) return stocks def _cal_price(self, base_p, diff): return float(base_p + diff) / 100 if __name__ == '__main__': from pytdx.hq import TdxHq_API api = TdxHq_API() with api.connect(): #print(api.to_df(api.get_security_quotes([(0, '102672'), (0, '002672')]))) print( api.to_df(api.get_security_quotes([(0, '101612'), (0, '002672')])))
class Engine: def __init__(self, *args, **kwargs): if kwargs.pop('best_ip', False): self.ip = self.best_ip else: self.ip = '14.17.75.71' self.ip = kwargs.pop('ip', '14.17.75.71') self.thread_num = kwargs.pop('thread_num', 1) if not PY2 and self.thread_num != 1: self.use_concurrent = True else: self.use_concurrent = False self.api = TdxHq_API(args, kwargs) if self.use_concurrent: self.apis = [ TdxHq_API(args, kwargs) for i in range(self.thread_num) ] self.executor = ThreadPoolExecutor(self.thread_num) def connect(self): self.api.connect(self.ip) if self.use_concurrent: for api in self.apis: api.connect(self.ip) return self def __enter__(self): return self def exit(self): self.api.disconnect() if self.use_concurrent: for api in self.apis: api.disconnect() def __exit__(self, exc_type, exc_val, exc_tb): self.api.disconnect() if self.use_concurrent: for api in self.apis: api.disconnect() def quotes(self, code): code = [code] if not isinstance(code, list) else code code = self.security_list[self.security_list.code.isin( code)].index.tolist() data = [ self.api.to_df( self.api.get_security_quotes(code[80 * pos:80 * (pos + 1)])) for pos in range(int(len(code) / 80) + 1) ] return pd.concat(data) # data = data[['code', 'open', 'high', 'low', 'price']] # data['datetime'] = datetime.datetime.now() # return data.set_index('code', drop=False, inplace=False) def stock_quotes(self): code = self.stock_list.index.tolist() if self.use_concurrent: res = { self.executor.submit(self.apis[pos % self.thread_num].get_security_quotes, code[80 * pos:80 * (pos + 1)]) \ for pos in range(int(len(code) / 80) + 1)} return pd.concat([self.api.to_df(dic.result()) for dic in res]) else: data = [ self.api.to_df( self.api.get_security_quotes(code[80 * pos:80 * (pos + 1)])) for pos in range(int(len(code) / 80) + 1) ] return pd.concat(data) @lazyval def security_list(self): return pd.concat([ pd.concat([ self.api.to_df(self.api.get_security_list( j, i * 1000)).assign(sse=0 if j == 0 else 1).set_index( ['sse', 'code'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1) ], axis=0) for j in range(2) ], axis=0) @lazyval def stock_list(self): aa = map(stock_filter, self.security_list.index.tolist()) return self.security_list[list(aa)] @lazyval def best_ip(self): return select_best_ip() @lazyval def concept(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_GN)) @lazyval def index(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_SZ)) @lazyval def fengge(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_FG)) @lazyval def customer_block(self): return CustomerBlockReader().get_df(CUSTOMER_BLOCK_PATH) @lazyval def gbbq(self): df = GbbqReader().get_df(GBBQ_PATH).query('category == 1') df['datetime'] = pd.to_datetime(df['datetime'], format='%Y%m%d') return df def get_security_type(self, code): if code in self.security_list.code.values: return self.security_list[self.security_list.code == code]['sse'].as_matrix()[0] else: raise SecurityNotExists() def get_security_bars(self, code, freq, index=False): if index: exchange = self.get_security_type(code) func = self.api.get_index_bars else: exchange = get_stock_type(code) func = self.api.get_security_bars df = pd.DataFrame() if freq in ['1d', 'day']: freq = 9 elif freq in ['1m', 'min']: freq = 8 else: raise Exception("1d and 1m frequency supported only") res = [] start = 0 while True: data = func(freq, exchange, code, start, 800) if not data: break res = data + res start += 800 df = self.api.to_df(res).drop( ['year', 'month', 'day', 'hour', 'minute'], axis=1) df['datetime'] = pd.to_datetime(df.datetime) df['code'] = code return df.set_index('datetime') def _get_transaction(self, code, date): res = [] start = 0 while True: data = self.api.get_history_transaction_data( get_stock_type(code), code, start, 2000, date) if not data: break start += 2000 res = data + res if len(res) == 0: return pd.DataFrame() df = self.api.to_df(res).assign(date=date) df.index = pd.to_datetime(str(date) + " " + df["time"]) df['code'] = code return df.drop("time", axis=1) def time_and_price(self, code): start = 0 res = [] exchange = self.get_security_type(code) while True: data = self.api.get_transaction_data(exchange, code, start, 2000) if not data: break res = data + res start += 2000 df = self.api.to_df(res) df.time = pd.to_datetime( str(pd.to_datetime('today').date()) + " " + df['time']) df.loc[0, 'time'] = df.time[1] return df.set_index('time') @classmethod def minute_bars_from_transaction(cls, transaction, freq): if transaction.empty: return pd.DataFrame() data = transaction['price'].resample(freq, label='right', closed='left').ohlc() data['volume'] = transaction['vol'].resample(freq, label='right', closed='left').sum() data['code'] = transaction['code'][0] return fillna(data) def get_k_data(self, code, start, end, freq): if isinstance(start, str) or isinstance(end, str): start = pd.Timestamp(start) end = pd.Timestamp(end) sessions = pd.date_range(start, end) trade_days = map(int, sessions.strftime("%Y%m%d")) if freq == '1m': freq = '1 min' if freq == '1d': freq = '24 H' res = [] for trade_day in trade_days: df = Engine.minute_bars_from_transaction( self._get_transaction(code, trade_day), freq) if df.empty: continue res.append(df) if len(res) != 0: return pd.concat(res) return pd.DataFrame()
class StdQuotes(object): """股票市场实时行情""" bestip = ('47.103.48.45', 7709) def __init__(self, **kwargs): try: default = settings.get('SERVER').get('HQ')[0] self.bestip = config.get('BESTIP').get('HQ', default) except ValueError: self.config = None self.client = TdxHq_API(**kwargs) def traffic(self): with self.client.connect(*self.bestip): return self.client.get_traffic_stats() def quotes(self, symbol=[]): ''' 获取实时日行情数据 :param symbol: 股票代码 :return: pd.dataFrame or None ''' logger.debug(type(logger)) if type(symbol) is str: symbol = [symbol] with self.client.connect(*self.bestip): symbol = get_stock_markets(symbol) result = self.client.get_security_quotes(symbol) return to_data(result) def bars(self, symbol='000001', frequency='9', start='0', offset='100'): ''' 获取实时日K线数据 :param symbol: 股票代码 :param frequency: 数据类别 :param market: 证券市场 :param start: 开始位置 :param offset: 每次获取条数 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_security_bars(int(frequency), int(market), str(symbol), int(start), int(offset)) return to_data(result) def stock_count(self, market=MARKET_SH): ''' 获取市场股票数量 :param market: 股票市场代码 sh 上海, sz 深圳 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): result = self.client.get_security_count(market=market) return result def stocks(self, market=MARKET_SH): ''' 获取股票列表 :param market: :return: ''' with self.client.connect(*self.bestip): counts = self.client.get_security_count(market=market) stocks = None for start in tqdm(range(0, counts, 1000)): result = self.client.get_security_list(market=market, start=start) stocks = pandas.concat( [stocks, to_data(result)], ignore_index=True) if start > 1 else to_data(result) return stocks def index_bars(self, symbol='000001', frequency='9', start='0', offset='100'): ''' 获取指数k线 :param symbol: :param frequency: :param start: :param offset: :return: ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_index_bars(frequency=frequency, market=market, code=symbol, start=start, count=offset) return to_data(result) def minute(self, symbol=''): ''' 获取实时分时数据 :param market: 证券市场 :param symbol: 股票代码 :return: pd.DataFrame ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_minute_time_data(market=market, code=symbol) return to_data(result) def minutes(self, symbol='', date='20191023'): ''' 分时历史数据 :param market: :param symbol: :param date: :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_history_minute_time_data(market=market, code=symbol, date=date) return to_data(result) def transaction(self, symbol='', start=0, offset=10): ''' 查询分笔成交 :param market: 市场代码 :param symbol: 股票代码 :param start: 起始位置 :param offset: 请求数量 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_transaction_data(int(market), symbol, int(start), int(offset)) return to_data(result) def transactions(self, symbol='', start=0, offset=10, date='20170209'): ''' 查询历史分笔成交 参数:市场代码, 股票代码,起始位置,日期 数量 如: 0,000001,0,10,20170209 :param symbol: 股票代码 :param start: 起始位置 :param offset: 数量 :param date: 日期 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol, string=False) result = self.client.get_history_transaction_data(market=market, code=symbol, start=start, count=offset, date=date) return to_data(result) def F10C(self, symbol=''): ''' 查询公司信息目录 :param market: 市场代码 :param symbol: 股票代码 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_company_info_category(int(market), symbol) return result def F10(self, symbol='', name=''): ''' 读取公司信息详情 :param name: 公司 F10 标题 :param symbol: 股票代码 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): result = {} market = get_stock_market(symbol, string=False) frequency = self.client.get_company_info_category( int(market), symbol) if name: for x in frequency: if x['name'] == name: return self.client.get_company_info_content( market=market, code=symbol, filename=x['filename'], start=x['start'], length=x['length']) for x in frequency: result[x['name']] = self.client.get_company_info_content( market=market, code=symbol, filename=x['filename'], start=x['start'], length=x['length']) else: pass return result def xdxr(self, symbol=''): ''' 读取除权除息信息 :param market: 市场代码 :param symbol: 股票代码 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_xdxr_info(int(market), symbol) return to_data(result) def finance(self, symbol='000001'): ''' 读取财务信息 :param symbol: :return: ''' with self.client.connect(*self.bestip): market = get_stock_market(symbol) result = self.client.get_finance_info(market=market, code=symbol) return to_data(result) def k(self, symbol='', begin=None, end=None): ''' 读取k线信息 :param symbol: :param begin: 开始日期 :param end: 截止日期 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): result = self.client.get_k_data(symbol, begin, end) return to_data(result) def index(self, symbol='000001', market=MARKET_SH, frequency='9', start=1, offset=2): ''' 获取指数k线 K线种类: - 0 5分钟K线 - 1 15分钟K线 - 2 30分钟K线 - 3 1小时K线 - 4 日K线 - 5 周K线 - 6 月K线 - 7 1分钟 - 8 1分钟K线 - 9 日K线 - 10 季K线 - 11 年K线 :param symbol: 股票代码 :param frequency: 数据类别 :param market: 证券市场 :param start: 开始位置 :param offset: 每次获取条数 :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): result = self.client.get_index_bars(int(frequency), int(market), str(symbol), int(start), int(offset)) return to_data(result) def block(self, tofile="block.dat"): ''' 获取证券板块信息 :param tofile: :return: pd.dataFrame or None ''' with self.client.connect(*self.bestip): result = self.client.get_and_parse_block_info(tofile) return to_data(result)
class PytdxApi: """TDX数据服务类""" def __init__(self): """Constructor""" self.connect_status: bool = False self.login_status: bool = False self.hq_api = None # 行情API self.conc_code_num = 50 # 并发获取行情的股票个数 # 行情订阅 self.active = False self.run_subscribe = Thread(target=self.get_realtime_data) self.symbols = list() self.symbols_split = list() def connect_api(self, host: str = "", port: int = 0): """连接行情api""" # 连接行情API并检查连接情况 try: if not self.connect_status: self.hq_api = TdxHq_API() self.hq_api.connect(host, port) self.connect_status = True self.login_status = True self.subscribe_start() except Exception as e: return e def get_realtime_quotes(self, quotes_list: list): """获取实时行情数据""" data = self.hq_api.get_security_quotes(quotes_list) return data def get_realtime_data(self): """获取实时行情切片""" try: while self.active: if not self.symbols_split: sleep(1) continue data = list() for symbols in self.symbols_split: d = self.get_realtime_quotes(symbols) data.extend(d) self.on_tick_data(data) sleep(2) except: error = dict() error["error_id"] = "pytdx" error["error_msg"] = "行情订阅失败" self.on_error(error) def get_transaction_count(self, market: int) -> int: """ 查询市场标的数量 """ return self.hq_api.get_security_count(market) def get_transaction_list(self, market: int, start: int) -> list: """查询市场标的列表""" return self.hq_api.get_security_list(market, start) def subscribe_start(self): """启动行情订阅""" self.active = True self.run_subscribe.start() def subscribe(self, symbol: Any): """订阅行情数据""" if isinstance(symbol, tuple): if symbol not in self.symbols: self.symbols.append(symbol) elif isinstance(symbol, list): for s in symbol: if s not in self.symbols: self.symbols.append(s) else: error = dict() error["error_id"] = "pytdx" error["error_msg"] = f"订阅标的代码格式不正确{symbol}" self.on_error(error) return symbol_split = self.get_code_split() self.symbols_split = copy(symbol_split) def subscribe_close(self): """关闭订阅""" if self.active: self.active = False self.run_subscribe.join() def get_transaction_info(self): """获取所有合约信息""" for exchange in list(exchange_map.values()): count = self.get_transaction_count(exchange) for c in range(0, count, 1000): symbols = self.get_transaction_list(exchange, c) for symbol in symbols: symbol["exchange"] = exchange if symbol["code"][:2] in ["60", "30", "688", "00"]: symbol["product"] = 3 else: symbol["product"] = 2 self.on_contract_info(symbol, False) self.on_contract_info({"exchange": exchange}, True) def get_all_stock(self): """获取所有股票数据""" stocks = list() for exchange in list(exchange_map.values()): count = self.get_transaction_count(exchange) for s in range(0, count, 1000): d = self.get_transaction_list(exchange, s) stocks.extend(d) l = len(stocks) - 1 for i, stock in enumerate(stocks): if stock["code"][:1] in ["60", "30", "688", "00"]: if i == l: self.on_contract_info(stock, True) else: self.on_contract_info(stock, False) def on_contract_info(self, data: dict, last: bool) -> None: """""" pass def on_tick_data(self, data): """订阅数据处理""" pass def on_error(self, err): """接口错误处理""" pass @staticmethod def generate_symbols(symbols: list): """组装symbols数据,pytdx接收的是以市场代码和标的代码组成的元祖的list""" new_symbols = [] for symbol in symbols: code, exchange = symbol.split(".") new_symbol = (exchange_map[exchange], code) new_symbols.append(new_symbol) return new_symbols @staticmethod def get_fast_ip(): """获取最快IP""" host = "210.51.39.201" port = 7709 return host, port @staticmethod def check_symbol(symbol: str): """检查标的格式""" if symbol: code, market = symbol.split(".") market = exchange_map.get(market) return code, market else: return False def get_code_split(self): """获得切割好的股票代码段""" code_split_list = [] for i in range(0, len(self.symbols) + 1, self.conc_code_num): code_split = self.symbols[i : i + self.conc_code_num] code_split_list.append(code_split) return code_split_list def exit(self): """数据服务关闭""" # 关闭订阅 self.subscribe_close() # 关闭接口 self.login_status = False self.connect_status = False self.hq_api.disconnect() self.hq_api = None
]) stocks.append(one_stock) return stocks def _cal_price(self, base_p, diff): return float(base_p + diff) / 100 def _format_time(self, time_stamp): """ format time from reversed_bytes0 by using method from https://github.com/rainx/pytdx/issues/187 """ time = time_stamp[:-6] + ':' if int(time_stamp[-6:-4]) < 60: time += '%s:' % time_stamp[-6:-4] time += '%06.3f' % (int(time_stamp[-4:]) * 60 / 10000.0) else: time += '%02d:' % (int(time_stamp[-6:]) * 60 / 1000000) time += '%06.3f' % ( (int(time_stamp[-6:]) * 60 % 1000000) * 60 / 1000000.0) return time if __name__ == '__main__': from pytdx.hq import TdxHq_API api = TdxHq_API() with api.connect('182.131.7.211', 7709): #print(api.to_df(api.get_security_quotes([(0, '102672'), (0, '002672')]))) print( api.to_df(api.get_security_quotes([(0, '000677'), (0, '002672')])))
##pip install pytdx from pytdx.hq import TdxHq_API api = TdxHq_API() api.connect('59.173.18.140', 7709) print("获取股票行情") data = api.get_k_data('000002', '2005-07-01', '2017-07-10') data2 = api.get_xdxr_info(1, '600300') print(data2) print("获取股票行情") stocks = api.get_security_quotes([(0, "000002"), (1, "600300")]) print(stocks) print("获取k线") data = api.get_security_bars(9, 0, '000001', 4, 3) print(data) print("获取 深市 股票数量") print(api.get_security_count(0)) print("获取股票列表") stocks = api.get_security_list(1, 255) print(stocks) print("获取指数k线") data = api.get_index_bars(9, 1, '000001', 1, 2) print(data) print("查询分时行情") data = api.get_minute_time_data(1, '600300')
class TdxData: def __init__(self): self.api = TdxHq_API(heartbeat=True) self.dbUtil = DBUtil.getInstance() def get_security_quotes(self, code, type): return self.api.get_security_quotes([(type, code)]) # 支持板块及个股 def days(self, code, type, bk=False, all=False, day=5): category = int(config.getByKey('TDX_CATEGORY')) try: with self.api.connect(TDX_IP, TDX_PORT): data = [] if all: if bk: for i in range(10): data += self.api.get_index_bars( category, type, code, (9 - i) * 800, 800) else: for i in range(10): data += self.api.get_security_bars( category, type, code, (9 - i) * 800, 800) if len(data) > 0: df = self.api.to_df(data).drop([ 'amount', 'year', 'month', 'day', 'hour', 'minute' ], axis=1) df['trade_date'] = df['datetime'].apply( lambda x: x[0:10].replace('-', '')) df = df.drop(['datetime'], axis=1) df = df.sort_values(by=['trade_date'], axis=0, ascending=False) return df else: return self.api.to_df(data) else: if bk: data = self.api.get_index_bars(category, type, code, 0, day) # 返回DataFrame else: data = self.api.get_security_bars( category, type, code, 0, day) if len(data) > 0: df = self.api.to_df(data).drop([ 'amount', 'year', 'month', 'day', 'hour', 'minute' ], axis=1) df['trade_date'] = df['datetime'].apply( lambda x: x[0:10].replace('-', '')) df = df.drop(['datetime'], axis=1) df = df.sort_values(by=['trade_date'], axis=0, ascending=False) return df else: return self.api.to_df(data) except Exception as e: logging.info("暂不支持类型,代码:%s:%s" % (code, e)) return self.api.to_df([]) # F10 查询公司信息目录 def get_company_info_category(self, code, type): with self.api.connect(TDX_IP, TDX_PORT): df = pd.DataFrame(self.api.get_company_info_category(type, code)) df['txt'] = None return df return [] def get_company_info_content(self, code, type, df): with self.api.connect(TDX_IP, TDX_PORT): return self.api.get_company_info_content(type, code, df['filename'].values[0], df['start'].values[0], df['length'].values[0]) return "" # 查询财务数据 def get_finance_info(self, code, type): with self.api.connect(TDX_IP, TDX_PORT): return self.api.get_finance_info(type, code) return '' # 每年更新一次,板块个股关系 def updateBk(self): with self.api.connect(TDX_IP, TDX_PORT): """ # 获取股票所属板块信息 # 板块相关参数 BLOCK_SZ = "block_zs.dat" BLOCK_FG = "block_fg.dat" BLOCK_GN = "block_gn.dat" BLOCK_DEFAULT = "block.dat" """ bk_zs = self.api.to_df( self.api.get_and_parse_block_info("block_zs.dat")) #指数板块 bk_fg = self.api.to_df( self.api.get_and_parse_block_info("block_fg.dat")) #风格板块 bk_gn = self.api.to_df( self.api.get_and_parse_block_info("block_gn.dat")) #概念板块 bk_default = self.api.to_df( self.api.get_and_parse_block_info("block.dat")) # 默认 self.dbUtil.to_sql(bk_gn, 'stock_bk_gn', if_exists='replace', index=False, dtype=STOCK_BK_DTYPE) self.dbUtil.to_sql(bk_fg, 'stock_bk_fg', if_exists='replace', index=False, dtype=STOCK_BK_DTYPE) self.dbUtil.to_sql(bk_zs, 'stock_bk_zs', if_exists='replace', index=False, dtype=STOCK_BK_DTYPE) self.dbUtil.to_sql(bk_default, 'stock_bk_default', if_exists='replace', index=False, dtype=STOCK_BK_DTYPE) # 获取股票列表 tmp1 = self.api.to_df(self.api.get_security_list(0, 0)) # 深圳 tmp1['type'] = 0 tmp2 = self.api.to_df(self.api.get_security_list(1, 0)) # 上海 tmp2['type'] = 1 tmp = tmp1.append(tmp2) self.dbUtil.to_sql(tmp, 'stock_bk', if_exists='replace', index=False, dtype=STOCK_BK) def updateGD(self, code, type): url = 'http://emweb.securities.eastmoney.com/PC_HSF10/ShareholderResearch/ShareholderResearchAjax?code=%s%s' % ( type.lower(), code) html = urllib.request.urlopen(url).read() # 将字符串转换成字典 data = json.loads(html.decode('utf-8')) # gdrs 股东人数,sdgd 十大股东 ,sdltgd 十大流通股东 df_gdrs = pd.DataFrame(data['gdrs']) df_gdrs['code'] = code try: db_df_gdrs = self.dbUtil.read_sql( "select * from stock_gdrs where code ='%s'" % code) # 数据合并 df_gdrs = df_gdrs.append(db_df_gdrs).drop_duplicates( subset=['code', 'rq', 'gdmc'], keep='last') except Exception as e: pass self.dbUtil.to_sql(df_gdrs, 'stock_gdrs', if_exists='append', index=False, dtype=STOCK_GDRS_DTYPE) sdgd = [] for i in range(len(data['sdgd'])): sdgd += data['sdgd'][i]['sdgd'] df_sdgd = pd.DataFrame(sdgd) df_sdgd['code'] = code try: db_df_sdgd = self.dbUtil.read_sql( "select * from stock_sdgd where code ='%s'" % code) df_sdgd = df_sdgd.append(db_df_sdgd).drop_duplicates( subset=['code', 'rq', 'gdmc'], keep='last') except Exception as e: pass self.dbUtil.to_sql(df_sdgd, 'stock_sdgd', if_exists='append', index=False, dtype=STOCK_SDGD_DTYPE) sdltgd = [] for i in range(len(data['sdltgd'])): sdltgd += data['sdltgd'][i]['sdltgd'] df_sdltgd = pd.DataFrame(sdltgd) df_sdltgd['code'] = code # 获取后与数据库中的数据进行merge,首次表不存在,会抛异常 try: db_df_sdltgd = self.dbUtil.read_sql( "select * from stock_sdltgd where code ='%s'" % code) df_sdltgd = df_sdltgd.append(db_df_sdltgd).drop_duplicates( subset=['code', 'rq', 'gdmc'], keep='last') except Exception as e: pass self.dbUtil.to_sql(df_sdltgd, 'stock_sdltgd', if_exists='append', index=False, dtype=STOCK_SDGD_DTYPE) # 没季度更新一次 def updateGDs(self): codes = self.dbUtil.read_sql("select ts_code from stock_basic") tmp = codes['ts_code'].str.split('.', expand=True) for index, row in tmp.iterrows(): try: self.updateGD(row[0], row[1]) logging.info('%s更新结束,当前索引%s' % (row[0], index)) except Exception as e: logging.info('%s更新失败,当前索引%s' % (row[0], index)) # 分红 # 分红地址http://data.eastmoney.com/yjfp/201812.html def updateFh(self, rq): url = 'http://data.eastmoney.com/DataCenter_V3/yjfp/getlist.ashx?filter=(ReportingPeriod=^%s^)' % rq html = requests.get(url) # 将字符串转换成字典 data = json.loads(html.text)['data'] if len(data) == 0: return 0 df = pd.DataFrame(data) df['ReportingPeriod'] = df['ReportingPeriod'].apply(lambda x: x[0:10]) # 首次需要将df_fh制空,因为表还不存在 if self.dbUtil.is_exist("stock_fh"): db_fh = self.dbUtil.read_sql( "select * from stock_fh where ReportingPeriod = '%s'" % df['ReportingPeriod'][0]) if db_fh.empty: # 不存在当前日期的分红信息,进行拼接 self.dbUtil.to_sql(df, 'stock_fh', if_exists='append', index=False) return 1 else: pass else: self.dbUtil.to_sql(df, 'stock_fh', if_exists='append', index=False) return 1 # 更新历年分红 def updateFhYears(self): now = int(time.strftime("%Y", time.localtime())) + 1 lastYear = int(self._getFhMaxYear()) for i in range(lastYear, now): #初始化时开启 type = self.updateFh('%s-06-30' % i) logging.info('%s-06-30%s' % (i, '成功' if type == 1 else '失败')) self.updateFh('%s-12-31' % i) logging.info('%s-12-31%s' % (i, '成功' if type == 1 else '失败')) def _getFhMaxYear(self): if self.dbUtil.is_exist('stock_fh'): try: df = self.dbUtil.read_sql( 'select substr(max(t.ReportingPeriod ),0,5) year from stock_fh t' ) return df['year'][0].values except Exception as e: pass return 1991 @classmethod def getInstance(cls): if not hasattr(TdxData, "_instance"): TdxData._instance = TdxData() return TdxData._instance
class PYTDXService(): """pytdx数据服务类""" def __init__(self): """Constructor""" self.connected = False # 数据服务连接状态 self.hq_api = None # 行情API def connect_api(self): """连接API""" # 连接增强行情API并检查连接情况 try: if not self.connected: host = SETTINGS["TDX_HOST"] port = SETTINGS["TDX_PORT"] self.hq_api = TdxHq_API() self.hq_api.connect(host, port) self.connected = True return True except Exception: raise ConnectionError("pytdx连接错误") def get_realtime_data(self, symbol: str): """获取股票实时数据""" try: symbols = self.generate_symbols(symbol) df = self.hq_api.to_df(self.hq_api.get_security_quotes(symbols)) return df except Exception: raise ValueError("股票数据获取失败") def get_history_transaction_data(self, symbol, date): """ 查询历史分笔数据 get_history_transaction_data(TDXParams.MARKET_SZ, '000001', 0, 10, 20170209) 参数:市场代码, 股票代码, 起始位置, 数量, 日期 输出[time, price, vol, buyorsell(0:buy, 1:sell, 2:平)] """ # 获得标的 code, market = self.check_symbol(symbol) # 设置参数 check_date = int(date) count = 2000 data_list = [] position = [6000, 4000, 2000, 0] for start in position: data = self.hq_api.to_df( self.hq_api.get_history_transaction_data( market, code, start, count, check_date)) data_list.append(data) df = pd.concat(data_list) df.drop_duplicates(inplace=True) return df @staticmethod def generate_symbols(symbol: str): """组装symbols数据,pytdx接收的是以市场代码和标的代码组成的元祖的list""" new_symbols = [] code, exchange = symbol.split('.') new_symbols.append((exchange_map[exchange], code)) return new_symbols @staticmethod def check_symbol(symbol: str): """检查标的格式""" if symbol: code, market = symbol.split('.') market = exchange_map.get(market) return code, market else: return False def close(self): """数据服务关闭""" self.connected = False self.hq_api.disconnect()
class Engine: concurrent_thread_count = 50 def __init__(self, *args, **kwargs): if 'ip' in kwargs: self.ip = kwargs.pop('ip') else: if kwargs.pop('best_ip', False): self.ip = self.best_ip else: self.ip = '14.17.75.71' if 'concurrent_thread_count' in kwargs: self.concurrent_thread_count = kwargs.pop( 'concurrent_thread_count', 50) self.thread_num = kwargs.pop('thread_num', 1) self.api = TdxHq_API(args, kwargs, raise_exception=True) def connect(self): self.api.connect(self.ip) return self def __enter__(self): return self def exit(self): self.api.disconnect() def __exit__(self, exc_type, exc_val, exc_tb): self.api.disconnect() def quotes(self, code): code = [code] if not isinstance(code, list) else code code = self.security_list[self.security_list.code.isin( code)].index.tolist() data = [ self.api.to_df( self.api.get_security_quotes(code[80 * pos:80 * (pos + 1)])) for pos in range(int(len(code) / 80) + 1) ] return pd.concat(data) # data = data[['code', 'open', 'high', 'low', 'price']] # data['datetime'] = datetime.datetime.now() # return data.set_index('code', drop=False, inplace=False) def stock_quotes(self): code = self.stock_list.index.tolist() data = [ self.api.to_df( self.api.get_security_quotes(code[80 * pos:80 * (pos + 1)])) for pos in range(int(len(code) / 80) + 1) ] return pd.concat(data) @lazyval def security_list(self): return pd.concat([ pd.concat([ self.api.to_df(self.api.get_security_list( j, i * 1000)).assign(sse=0 if j == 0 else 1).set_index( ['sse', 'code'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1) ], axis=0) for j in range(2) ], axis=0) @lazyval def stock_list(self): aa = map(stock_filter, self.security_list.index.tolist()) return self.security_list[list(aa)] @lazyval def best_ip(self): return select_best_ip() @lazyval def concept(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_GN)) @lazyval def index(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_SZ)) @lazyval def fengge(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_FG)) @lazyval def block(self): return self.api.to_df( self.api.get_and_parse_block_info(TDXParams.BLOCK_DEFAULT)) @lazyval def customer_block(self): return CustomerBlockReader().get_df(CUSTOMER_BLOCK_PATH) def xdxr(self, code): df = self.api.to_df( self.api.get_xdxr_info(self.get_security_type(code), code)) if df.empty: return df df['datetime'] = pd.to_datetime((df.year * 10000 + df.month * 100 + df.day).apply(lambda x: str(x))) return df.drop(['year', 'month', 'day'], axis=1).set_index('datetime') @lazyval def gbbq(self): df = GbbqReader().get_df(GBBQ_PATH).query('category == 1') df['datetime'] = pd.to_datetime(df['datetime'], format='%Y%m%d') return df def get_security_type(self, code): if code in self.security_list.code.values: return self.security_list[self.security_list.code == code]['sse'].as_matrix()[0] else: raise SecurityNotExists() @retry(3) def get_security_bars(self, code, freq, start=None, end=None, index=False): if index: exchange = self.get_security_type(code) func = self.api.get_index_bars else: exchange = get_stock_type(code) func = self.api.get_security_bars if start: start = start.tz_localize(None) if end: end = end.tz_localize(None) if freq in ['1d', 'day']: freq = 9 elif freq in ['1m', 'min']: freq = 8 else: raise Exception("1d and 1m frequency supported only") res = [] pos = 0 while True: data = func(freq, exchange, code, pos, 800) if not data: break res = data + res pos += 800 if start and pd.to_datetime(data[0]['datetime']) < start: break try: df = self.api.to_df(res).drop( ['year', 'month', 'day', 'hour', 'minute'], axis=1) df['datetime'] = pd.to_datetime(df.datetime) df.set_index('datetime', inplace=True) if freq == 9: df.index = df.index.normalize() except ValueError: # 未上市股票,无数据 logger.warning("no k line data for {}".format(code)) # return pd.DataFrame({ # 'amount': [0], # 'close': [0], # 'open': [0], # 'high': [0], # 'low': [0], # 'vol': [0], # 'code': code # }, # index=[start] # ) return pd.DataFrame() close = [df.close.values[-1]] if start: df = df.loc[lambda df: start <= df.index] if end: df = df.loc[lambda df: df.index.normalize() <= end] if df.empty: # return pd.DataFrame({ # 'amount': [0], # 'close': close, # 'open': close, # 'high': close, # 'low': close, # 'vol': [0], # 'code': code # }, # index=[start] # ) return df else: if int(df['vol'][-1]) <= 0 and end == df.index[-1] and len( df) == 1: # 成交量为0,当天返回的是没开盘的数据 return pd.DataFrame() df['code'] = code return df def _get_transaction(self, code, date): res = [] start = 0 while True: data = self.api.get_history_transaction_data( get_stock_type(code), code, start, 2000, date) if not data: break start += 2000 res = data + res if len(res) == 0: return pd.DataFrame() df = self.api.to_df(res).assign(date=date) df.loc[0, 'time'] = df.time[1] df.index = pd.to_datetime(str(date) + " " + df["time"]) df['code'] = code return df.drop("time", axis=1) def time_and_price(self, code): start = 0 res = [] exchange = self.get_security_type(code) while True: data = self.api.get_transaction_data(exchange, code, start, 2000) if not data: break res = data + res start += 2000 df = self.api.to_df(res) df.time = pd.to_datetime( str(pd.to_datetime('today').date()) + " " + df['time']) df.loc[0, 'time'] = df.time[1] return df.set_index('time') @classmethod def minute_bars_from_transaction(cls, transaction, freq): if transaction.empty: return pd.DataFrame() mask = transaction.index < transaction.index[0].normalize( ) + pd.Timedelta('12 H') def resample(transaction): if transaction.empty: return pd.DataFrame() data = transaction['price'].resample(freq, label='right', closed='left').ohlc() data['volume'] = transaction['vol'].resample(freq, label='right', closed='left').sum() data['code'] = transaction['code'][0] return data morning = resample(transaction[mask]) afternoon = resample(transaction[~mask]) if morning.empty and afternoon.empty: return pd.DataFrame() if not afternoon.empty: morning.index.values[-1] = afternoon.index[0] - pd.Timedelta( '1 min') df = pd.concat([morning, afternoon]) return fillna(df) def _get_k_data(self, code, freq, sessions): trade_days = map(int, sessions.strftime("%Y%m%d")) if freq == '1m': freq = '1 min' if freq == '1d': freq = '24 H' res = [] concurrent_count = self.concurrent_thread_count jobs = [] for trade_day in trade_days: # df = Engine.minute_bars_from_transaction(self._get_transaction(code, trade_day), freq) reqevent = gevent.spawn(Engine.minute_bars_from_transaction, self._get_transaction(code, trade_day), freq) jobs.append(reqevent) if len(jobs) >= concurrent_count: gevent.joinall(jobs, timeout=30) for j in jobs: if j.value is not None and not j.value.empty: res.append(j.value) jobs.clear() gevent.joinall(jobs, timeout=30) for j in jobs: if j.value is not None and not j.value.empty: res.append(j.value) jobs.clear() if len(res) != 0: return pd.concat(res) return pd.DataFrame() def get_k_data(self, code, start, end, freq, check=True): if isinstance(start, str) or isinstance(end, str): start = pd.Timestamp(start) end = pd.Timestamp(end) if check: daily_bars = self.get_security_bars(code, '1d', start, end) if daily_bars is None or daily_bars.empty: return daily_bars sessions = daily_bars.index else: sessions = pd.bdate_range(start, end, weekmask='Mon Tue Wed Thu Fri') df = self._get_k_data(code, freq, sessions) def check_df(freq, df, daily_bars): if freq == '1m': need_check = pd.DataFrame({ 'open': df['open'].resample('1D').first(), 'high': df['high'].resample('1D').max(), 'low': df['low'].resample('1D').min(), 'close': df['close'].resample('1D').last(), 'volume': df['volume'].resample('1D').sum() }).dropna() else: need_check = df if daily_bars.shape[0] != need_check.shape[0]: logger.warning("{} merged {}, expected {}".format( code, need_check.shape[0], daily_bars.shape[0])) need_check = fillna( need_check.reindex(daily_bars.index, copy=False)) diff = daily_bars[['open', 'close']] == need_check[['open', 'close']] res = (diff.open) & (diff.close) sessions = res[res == False].index return sessions if not df.empty: if check: sessions = check_df(freq, df, daily_bars) if sessions.shape[0] != 0: logger.info( "fixing data for {}-{} with sessions: {}".format( code, freq, sessions)) fix = self._get_k_data(code, freq, sessions) df.loc[fix.index] = fix return df return df