pytdx icon indicating copy to clipboard operation
pytdx copied to clipboard

能否提供返回字段的含义

Open leegb opened this issue 8 years ago • 51 comments

感谢您的贡献,能否提供返回字段的含义,比如行情返回的reversed_bytes,active2,查看了代码,也没找到注释。另外,是否可解析出换手率数据。

leegb avatar Aug 20 '17 06:08 leegb

reversed_bytes 是和时间有关的信息,不过目前还无法正确还原为时间, active2 目前还无法解析..

至于具体的字段含义,暂时还没有精力一一整理,后续有时间的时候把主要接口的返回字段回加上一些说明

rainx avatar Aug 20 '17 09:08 rainx

@leegb 感谢关注.

rainx avatar Aug 20 '17 09:08 rainx

@rainx 期待你解析完成,不知是不是服务器不支持并发访问,我看了get_security_quotes()通过循环实现我通过它来获取即时行情费时太多,无法满足对市场的监控。

leegb avatar Aug 20 '17 09:08 leegb

通达信的协议里面有一个类似tcp头中的seq_no的序列号, 一个请求和一个应答回包含相同的seq_no, 一般在请求头的第二个字节,这个我目前并没有利用,如果按照这个设计的话,理论上可以在一个连接里面发送多条请求之后再接收应答信息(目前还未实现), 理论上python对线程并发的支持并不好,如果想要提高吞吐量,可以创建多个进程,每个进程一个独立的连接,分别读取不同的代码,这样的方式来获取行情信息可以提升单个服务器的吞吐量,当然更好的方法是连接到不同的服务器,这样的话可以分散服务器访问压力..

rainx avatar Aug 20 '17 11:08 rainx

@rainx 对通信协议不了解,之前用的是网易网页的API,获取一次全市场即时行情的时间也就几秒钟,但是最近不知道为什么变得非常慢,希望你能将一次发送多个代码,返回数据的功能开发出来,不胜感激。

leegb avatar Aug 20 '17 13:08 leegb

对于抓取全市场行情,暂时还无法提供对应的代码,目前来看,基本上提供了此功能的库很快都会被数据源方屏蔽,比如新浪level2行情,不建议大范围使用

对于一次发送多个代码,我们的程序本来就是支持的,只不过对与每次调用时发送代码数量上限有一定的限制,您可以酌情使用。。

In [8]: api.to_df(api.get_security_quotes([(0, "000001"), (1, "600300")]))
Out[8]: 
   market    code  active1  price  last_close  open  high  low  \
0       0  000001        0    0.0       10.44   0.0   0.0  0.0   
1       1  600300        0    0.0        5.52   0.0   0.0  0.0   

      reversed_bytes0  reversed_bytes1   ...     ask5  bid_vol5  ask_vol5  \
0  [184, 242, 223, 8]                0   ...      0.0         0         0   
1  [164, 150, 222, 8]                0   ...      0.0         0         0   

   reversed_bytes4  reversed_bytes5  reversed_bytes6  reversed_bytes7  \
0             (0,)                0             1054             1075   
1             (0,)                0              553              559   

   reversed_bytes8  reversed_bytes9  active2  
0             1029                0        0  
1              549                0        0  

[2 rows x 44 columns]

rainx avatar Aug 21 '17 01:08 rainx

全市场实时行情 是单指last_price吗

yutiansut avatar Aug 21 '17 04:08 yutiansut

@rainx api.get_security_list(1, 0)这个api可以呀

yutiansut avatar Aug 21 '17 04:08 yutiansut

@yutiansut 全市场api.get_security_quotes()的最新成交价

leegb avatar Aug 21 '17 08:08 leegb

@leegb 只是获取最新价用 get_security_list 就可以了,一次获取的也比较多

rainx avatar Aug 22 '17 02:08 rainx

@leegb api.get_security_quotes()如果只要最新成交价 这个的数据太多了 传输时间也是问题

yutiansut avatar Aug 22 '17 02:08 yutiansut

:)

rainx avatar Aug 24 '17 00:08 rainx

通达信的协议里面有一个类似tcp头中的seq_no的序列号, 一个请求和一个应答回包含相同的seq_no, 一般在请求头的第二个字节,这个我目前并没有利用,如果按照这个设计的话,理论上可以在一个连接里面发送多条请求之后再接收应答信息(目前还未实现)

能否保留seq_no,将请求/应答分离开来,使用asyncio,提高单一连接的吞吐量

zfsamzfsam avatar Aug 24 '17 06:08 zfsamzfsam

seq_no..这个我后续再加吧...因为暂时用同步获取感觉速度也还可以,另外就是有点担心抓取的量太大被服务器block..

rainx avatar Aug 24 '17 08:08 rainx

获取个数多的话,单机可以考虑用python的多进程map-reduce向多个服务器发起请求。用futures.ProcessPoolExecutor()的map方法。代码几乎不用修改,很简单。 目前这几天正在测试,用M个进程实时获取数据,每个进程随机从N(N>3M)个服务器中选取一个。 用了API后,数据获取模式会跟一般客户端有明显区别,如果对单个服务器扒太狠,当心TDX提出限制措施,那时就变成魔高一尺,道高一丈的游戏了。

solenbanson avatar Sep 06 '17 11:09 solenbanson

用yutiansut 的代码 https://github.com/yutiansut/QUANTAXIS/blob/master/QUANTAXIS/QAFetch/QATdx.py#L53 修改了一个函数: tdx_get_servers(),用途是测试ip列表中的服务器速度,返回连接速度较快的n个列表。 使用的时候,,一般这样:

servers=tdx_get_servers(n=10)
api.connect(server[randint(1,10)],7709)

把servers=tdx_get_servers()放在程序头部 在程序内编写涉及到api.connect时,用随机函数从该列表中取得地址

应该可以部分缓解对单个服务器的压力。 更进一步的数据读取采取多线程或者进程的话,注意测试servers作为参数是否传递进线程或者进程。

from pytdx.hq import TdxHq_API
from datetime import datetime,timedelta
import pandas as pd
#import numpy as np

tdx_ip = [
'101.227.73.20',
'202.108.253.130',
......
]

def ping_tdx(ip):
    t1 = datetime.now()
    api = TdxHq_API()
    try:
        with api.connect(ip, 7709):
            api.get_index_bars(9, 1, '000001', 0, 1)            
        return (datetime.now() - t1).total_seconds()
    except:
        return 9999

def tdx_get_servers( n=5, df=False):
    lt = []
    for t_ip,t_s in zip(tdx_ip,map(ping_tdx,tdx_ip)):
        lt.append([t_ip,t_s])
    server_list = pd.DataFrame(lt).sort_values(by=1)
    if df:
        return server_list
    server_list = server_list[server_list[1] < 0.2]
    return list(server_list.iloc[0:n,0].values)

参数 n:返回服务器数量,默认5个 df:测试开关,设为True时返回所有结果的DataFrame

solenbanson avatar Sep 06 '17 15:09 solenbanson

我不是写了吗 @solensolen https://github.com/yutiansut/QUANTAXIS/blob/master/QUANTAXIS/QAFetch/QATdx.py#L53

def ping(ip):
    api = TdxHq_API()
    __time1 = datetime.datetime.now()
    try:
        with api.connect(ip, 7709):
            api.get_security_bars(9, 0, '000001', 0, 1)
        return datetime.datetime.now() - __time1
    except:
        return datetime.timedelta(9, 9, 0)


def select_best_ip():
    QA_util_log_info('Selecting the Best Server IP of TDX')
    listx = ['180.153.18.170', '180.153.18.171', '202.108.253.130', '202.108.253.131',
             '60.191.117.167', '115.238.56.198', '218.75.126.9', '115.238.90.165',
             '124.160.88.183', '60.12.136.250', '218.108.98.244', '218.108.47.69',
             '14.17.75.71', '180.153.39.51']
    data = [ping(x) for x in listx]
    QA_util_log_info('===The BEST SERVER is :  %s ===' %
                     (listx[data.index(min(data))]))
    return listx[data.index(min(data))]

yutiansut avatar Sep 06 '17 15:09 yutiansut

@solensolen 我这是找到最快的那个

yutiansut avatar Sep 06 '17 15:09 yutiansut

嗯,就是参考您代码改的,因为需要一次获取多个列表。主要为了实现单线程或多线程运行中随机更换tdx服务器。

另外防止股票‘000001’休市可能导致异常,ping里面改成获取指数api.get_index_bars

solenbanson avatar Sep 06 '17 16:09 solenbanson

不会的 他是start0 拿一条 所以今天停牌 也会有昨天的数据

如果你拿失败了(比如被封了) 重新运行这个代码 就能返回新的

yutiansut avatar Sep 06 '17 16:09 yutiansut

不过有个烦躁的是 服务器多的话 验证最优的时候 如果timeout比较多 会阻塞比较久

yutiansut avatar Sep 06 '17 16:09 yutiansut

确实,我单进程测试,30个服务器,都通的话4-5秒就结束。有2个TO,就要+4S左右了。如果更多TO,时间估计还要加。 如果TO服务器比例特别高,我这代码改两行,用多线程可以缓解。但你这面向公众的代码又不能随便采用多线程,到时不同的机器硬件出一堆其他问题。

solenbanson avatar Sep 06 '17 16:09 solenbanson

是的 最好是生产者消费者模式 不过有点小题大做 除非你对行情低延迟性要求很高 如果是存数据 就没关系了

yutiansut avatar Sep 06 '17 16:09 yutiansut

发现一个坑爹的情况,对于停牌股票,不同服务器的返回策略不一样: 有些是返回当前K线,但成交额为0或者一个很小的数。 有些返回停牌前的K线。

solenbanson avatar Sep 11 '17 08:09 solenbanson

@solensolen 哦? 哪个服务器? 地址有吗 我测一下

yutiansut avatar Sep 11 '17 08:09 yutiansut

没有记录.....比例很小,但可能会撞上。估计是某个券商的调整。加了一段代码进行判断才正常,把获取的最新记录的日期和当前日期比对,然后再根据成交量判断。

last_day = datetime.date(tt.iloc[-1,].name)
    if last_day == date.today():
        if tt.loc[last_day:,'amount'].sum() >1:
            return (code,tt.loc[last_day:,])
        else:
            return ('stop_'+code,'有返回当天数据但实际无成交量,判断停牌')
    else:
        return ('stop_'+code,'未返回当天数据,判断停牌')

solenbanson avatar Sep 11 '17 08:09 solenbanson

实际测试了一下,4s可以取完全部行情

user20171001 avatar Sep 27 '17 05:09 user20171001

理论上是700ms 不知道为啥这么慢

yutiansut avatar Sep 27 '17 06:09 yutiansut

@rainx active这个字段之前稍微纠结过一下,应该时间和tick相关的一个字段,active相同的话,其他字段的值都是一样的

hadrianl avatar Sep 27 '17 06:09 hadrianl

你说的是方向?

yutiansut avatar Sep 27 '17 07:09 yutiansut