diff --git a/hikyuu/fetcher/__init__.py b/hikyuu/fetcher/__init__.py new file mode 100644 index 00000000..e0b32f53 --- /dev/null +++ b/hikyuu/fetcher/__init__.py @@ -0,0 +1,8 @@ +# coding:utf-8 +# +# The MIT License (MIT) +# +# Created on: 2020-11-29 +# Author: fasiondog + +__version__ = "0.0.1" \ No newline at end of file diff --git a/hikyuu/fetcher/proxy.py b/hikyuu/fetcher/proxy.py new file mode 100644 index 00000000..8263db47 --- /dev/null +++ b/hikyuu/fetcher/proxy.py @@ -0,0 +1,14 @@ +# coding:utf-8 +# +# The MIT License (MIT) +# +# Created on: 2020-11-29 +# Author: fasiondog + + +def getProxy(): + """ + 返回代理地址,格式 :代理ip地址:代理端口号,如:183.164.239.57:4264 + 如无法获取时,返回 None + """ + return None \ No newline at end of file diff --git a/hikyuu/fetcher/stock/__init__.py b/hikyuu/fetcher/stock/__init__.py new file mode 100644 index 00000000..e0b32f53 --- /dev/null +++ b/hikyuu/fetcher/stock/__init__.py @@ -0,0 +1,8 @@ +# coding:utf-8 +# +# The MIT License (MIT) +# +# Created on: 2020-11-29 +# Author: fasiondog + +__version__ = "0.0.1" \ No newline at end of file diff --git a/hikyuu/fetcher/stock/zh_stock_a_sina.py b/hikyuu/fetcher/stock/zh_stock_a_sina.py new file mode 100644 index 00000000..c320a293 --- /dev/null +++ b/hikyuu/fetcher/stock/zh_stock_a_sina.py @@ -0,0 +1,66 @@ +# coding:utf-8 +# +# The MIT License (MIT) +# +# Created on: 2020-11-29 +# Author: fasiondog + +import requests + + +def parse_one_result(resultstr): + result = {} + if not resultstr: + return result + + if len(resultstr) <= 3 and resultstr[:3] != 'var': + return result + + a = resultstr.split(',') + if len(a) < 9: + return + + try: + tmp = a[0].split('"') + result['name'] = tmp[1] + + except Exception as e: + print(e) + + return result + + +def request_func(querystr): + try: + result = requests.get(querystr).text + except Exception as e: + print(result) + print(e) + return + + result = result.split('\n') + for tmpstr in result: + parse_one_result(tmpstr) + + return + + +def get_spot_from_sina(stocklist): + queryStr = "http://hq.sinajs.cn/list=" + max_size = 140 + count = 0 + tmpstr = queryStr + for stock in stocklist: + tmpstr += ("%s,") % (stock) + count = count + 1 + if count >= max_size: + request_func(tmpstr) + count = 0 + tmpstr = queryStr + + if tmpstr != queryStr: + request_func(tmpstr) + + +if __name__ == "__main__": + print("a") diff --git a/hikyuu/gui/HikyuuTDX.py b/hikyuu/gui/HikyuuTDX.py index fe21745a..511cd80b 100644 --- a/hikyuu/gui/HikyuuTDX.py +++ b/hikyuu/gui/HikyuuTDX.py @@ -22,6 +22,7 @@ from hikyuu.gui.data.UsePytdxImportToH5Thread import UsePytdxImportToH5Thread from hikyuu.gui.data.CollectThread import CollectThread from hikyuu.data import hku_config_template +from hikyuu.util.mylog import add_class_logger_handler class EmittingStream(QObject): @@ -125,14 +126,16 @@ class MyMainWindow(QMainWindow, Ui_MainWindow): ) con.setFormatter(FORMAT) logger_name_list = [ - self.__class__.__name__, CollectThread.__name__, UsePytdxImportToH5Thread.__name__, - UseTdxImportToH5Thread.__name__ + self.__class__.__name__, UsePytdxImportToH5Thread.__name__, + UseTdxImportToH5Thread.__name__, CollectThread.__name__ ] for name in logger_name_list: logger = logging.getLogger(name) logger.addHandler(con) logger.setLevel(logging.INFO) + #add_class_logger_handler(con, [CollectThread]) + def initUI(self): if self._capture_output: stream = EmittingStream(textWritten=self.normalOutputWritten) diff --git a/hikyuu/interactive.py b/hikyuu/interactive.py index 947080b9..5f8ff4be 100644 --- a/hikyuu/interactive.py +++ b/hikyuu/interactive.py @@ -378,7 +378,7 @@ def realtime_update_from_sina_qq(source): return count = 0 - urls = [] + #urls = [] tmpstr = queryStr for stock in sm: if stock.valid and stock.type in ( diff --git a/hikyuu/util/__init__.py b/hikyuu/util/__init__.py index ac9d5e30..ee70d339 100644 --- a/hikyuu/util/__init__.py +++ b/hikyuu/util/__init__.py @@ -9,4 +9,4 @@ #from singleton import Singleton -__all__ = ['mylog'] \ No newline at end of file +__all__ = ['mylog', 'check'] \ No newline at end of file diff --git a/hikyuu/util/check.py b/hikyuu/util/check.py index 007c0a72..2efe0147 100644 --- a/hikyuu/util/check.py +++ b/hikyuu/util/check.py @@ -18,8 +18,33 @@ class CheckError(Exception): def checkif(expression, message, excepion=None, **kwargs): + """如果 expression 为 True,则抛出异常。注意:该函数的判定和 assert 是相反的。 + + :param boolean expression: 判断条件 + :param str message: 异常注解信息 + :param Exception exception: 指定的异常类,为None时,为默认 CheckError 异常 + """ if expression: if excepion is None: raise CheckError(expression, message) else: raise excepion(message, **kwargs) + + +def HKU_CHECK(exp, msg): + if not exp: + raise CheckError(exp, msg) + + +def HKU_CHECK_THROW(expression, message, excepion=None, **kwargs): + """如果 expression 为 False,则抛出异常。 + + :param boolean expression: 判断条件 + :param str message: 异常注解信息 + :param Exception exception: 指定的异常类,为None时,为默认 CheckError 异常 + """ + if not expression: + if excepion is None: + raise CheckError(expression, message) + else: + raise excepion(message, **kwargs) diff --git a/hikyuu/util/mylog.py b/hikyuu/util/mylog.py index 2c773fbc..f09e8baa 100644 --- a/hikyuu/util/mylog.py +++ b/hikyuu/util/mylog.py @@ -2,88 +2,37 @@ # -*- coding: utf8 -*- # cp936 -""" -该模块除escapetime函数外,均来自SQLAlchemy,做了少量修改 - -Logging control and utilities. - -Control of logging for SA can be performed from the regular python logging -module. The regular dotted module namespace is used, starting at -'sqlalchemy'. For class-level logging, the class name is appended. - -The "echo" keyword parameter which is available on SQLA ``Engine`` -and ``Pool`` objects corresponds to a logger specific to that -instance only. - -E.g.:: - - engine.echo = True - -is equivalent to:: - - import logging - logger = logging.getLogger('sqlalchemy.engine.Engine.%s' % hex(id(engine))) - logger.setLevel(logging.DEBUG) - -""" - import logging import sys import time +from functools import wraps -def escapetime( func ): - def wrappedFunc( *args, **kargs ): + +def escapetime(func): + @wraps(func) + def wrappedFunc(*args, **kargs): starttime = time.time() try: print("\nCalling: %s" % func.__name__) return func(*args, **kargs) finally: endtime = time.time() - #print( "Called: %r" % func) - print( "Escaped time: %.4fs, %.2fm" % (endtime-starttime, (endtime-starttime)/60) ) + print("Escaped time: %.4fs, %.2fm" % (endtime - starttime, (endtime - starttime) / 60)) + return wrappedFunc -mylogger = logging.getLogger('my') +mylogger_name = 'hikyuu' +mylogger = logging.getLogger(mylogger_name) handler = logging.StreamHandler(sys.stdout) -handler.setFormatter(logging.Formatter( - '%(asctime)s %(levelname)s %(name)s %(message)s')) +handler.setFormatter( + logging.Formatter('%(asctime)-15s [%(levelname)s]: %(message)s [%(name)s::%(funcName)s]') +) mylogger.addHandler(handler) -def set_debug_mode(logtype='debug'): - global mylogger - if logtype == 'debug': - mylogger.setLevel(logging.DEBUG) - elif logtype == 'info': - mylogger.setLevel(logging.INFO) - elif logtype == 'warning': - mylogger.setLevel(logging.WARNING) - elif logtype == 'error': - mylogger.setLevel(logging.ERROR) - elif logtype == 'critical': - mylogger.setLevel(logging.CRITICAL) - else: - mylogger.setLevel(logging.ERROR) - -rootlogger = logging.getLogger('stock') -if rootlogger.level == logging.NOTSET: - rootlogger.setLevel(logging.WARN) - -default_enabled = False -def default_logging(name): - global default_enabled - if logging.getLogger(name).getEffectiveLevel() < logging.WARN: - default_enabled = True - - if not default_enabled: - default_enabled = True - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(logging.Formatter( - '%(asctime)s %(levelname)s %(name)s %(message)s')) - rootlogger.addHandler(handler) def class_logger(cls, enable=False): - logger = logging.getLogger(cls.__module__ + "." + cls.__name__) + logger = logging.getLogger("{}.{}".format(cls.__module__, cls.__name__)) if enable == 'debug': logger.setLevel(logging.DEBUG) elif enable == 'info': @@ -92,62 +41,15 @@ def class_logger(cls, enable=False): cls._should_log_info = logger.isEnabledFor(logging.INFO) cls.logger = logger -def instance_logger(instance, echoflag=None): - """create a logger for an instance. - - Warning: this is an expensive call which also results in a permanent - increase in memory overhead for each call. Use only for - low-volume, long-time-spanning objects. - + +def add_class_logger_handler(handler, class_list, level=logging.INFO): + """为指定的类增加日志 handler,并设定级别 + + :param handler: logging handler + :param class_list: 类列表 + :param level: 日志级别 """ - - # limit the number of loggers by chopping off the hex(id). - # many novice users unfortunately create an unlimited number - # of Engines in their applications which would otherwise - # cause the app to run out of memory. - name = "%s.%s.0x...%s" % (instance.__class__.__module__, - instance.__class__.__name__, - hex(id(instance))[-4:]) - - if echoflag is not None: - l = logging.getLogger(name) - if echoflag == 'debug': - default_logging(name) - l.setLevel(logging.DEBUG) - elif echoflag is True: - default_logging(name) - l.setLevel(logging.INFO) - elif echoflag is False: - l.setLevel(logging.NOTSET) - else: - l = logging.getLogger(name) - - if not l.handlers: - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(logging.Formatter( - '%(asctime)s %(levelname)s %(name)s %(message)s')) - l.addHandler(handler) - - instance._should_log_debug = l.isEnabledFor(logging.DEBUG) - instance._should_log_info = l.isEnabledFor(logging.INFO) - return l - -class echo_property(object): - __doc__ = """\ - When ``True``, enable log output for this element. - - This has the effect of setting the Python logging level for the namespace - of this element's class and object reference. A value of boolean ``True`` - indicates that the loglevel ``logging.INFO`` will be set for the logger, - whereas the string value ``debug`` will set the loglevel to - ``logging.DEBUG``. - """ - - def __get__(self, instance, owner): - if instance is None: - return self - else: - return instance._should_log_debug and 'debug' or (instance._should_log_info and True or False) - - def __set__(self, instance, value): - instance_logger(instance, echoflag=value) + for cls in class_list: + logger = logging.getLogger("{}.{}".format(cls.__module__, cls.__name__)) + logger.addHandler(handler) + logger.setLevel(level) diff --git a/sub_setup.py b/sub_setup.py index 203fd6d0..8fda5164 100644 --- a/sub_setup.py +++ b/sub_setup.py @@ -49,6 +49,8 @@ packages = [ 'hikyuu/data/sqlite_upgrade', 'hikyuu/data_driver', 'hikyuu/examples', + 'hikyuu/fetcher', + 'hikyuu/fetcher/stock', 'hikyuu/gui', 'hikyuu/gui/data', 'hikyuu/indicator', @@ -127,6 +129,7 @@ setup( 'gitpython', 'SQLAlchemy', 'mysql-connector-python', - 'pyperclip' + 'pyperclip', + 'requests' ], ) \ No newline at end of file