├── .bumpversion.cfg ├── .coveragerc ├── .gitignore ├── .pre-commit-config.yaml ├── .pylintrc ├── .travis.yml ├── LICENSE ├── Makefile ├── Pipfile ├── Pipfile.lock ├── README.md ├── easyquotation ├── __init__.py ├── api.py ├── basequotation.py ├── boc.py ├── daykline.py ├── helpers.py ├── hkqoute.py ├── jsl.py ├── sina.py ├── stock_codes.conf ├── tencent.py └── timekline.py ├── mypy.ini ├── requirements.txt ├── setup.py ├── test-requirements.txt └── tests ├── __init__.py ├── test_easyquotation.py ├── test_sina.py └── test_timekline.py /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.5.13 3 | commit = True 4 | files = easyquotation/__init__.py setup.py 5 | tag = True 6 | tag_name = {new_version} 7 | 8 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | include = easyquotation/* 4 | omit = tests/* 5 | 6 | [report] 7 | fail_under = -1 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bak 2 | .mypy_cache 3 | .pyre 4 | .pytest_cache 5 | yjb_account.json 6 | htt.json 7 | gft.json 8 | test.py 9 | ht_account.json 10 | .idea 11 | .vscode 12 | .ipynb_checkpoints 13 | Untitled.ipynb 14 | untitled.txt 15 | # Byte-compiled / optimized / DLL files 16 | __pycache__/ 17 | *.py[cod] 18 | account.json 19 | account.session 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | env/ 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | downloads/ 30 | eggs/ 31 | .eggs/ 32 | lib/ 33 | lib64/ 34 | parts/ 35 | sdist/ 36 | var/ 37 | *.egg-info/ 38 | .installed.cfg 39 | *.egg 40 | 41 | # PyInstaller 42 | # Usually these files are written by a python script from a template 43 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 44 | *.manifest 45 | *.spec 46 | 47 | # Installer logs 48 | pip-log.txt 49 | pip-delete-this-directory.txt 50 | 51 | # Unit test / coverage reports 52 | htmlcov/ 53 | .tox/ 54 | .coverage 55 | .coverage.* 56 | .cache 57 | nosetests.xml 58 | coverage.xml 59 | *,cover 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # cache 75 | tmp/ 76 | 77 | secrets/ 78 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | fail_fast: true 2 | repos: 3 | - repo: local 4 | hooks: 5 | - id: python_sort_imports 6 | name: python_sort_imports 7 | entry: pipenv run sort_imports 8 | language: system 9 | types: [python] 10 | - id: python_format 11 | name: python_format 12 | entry: pipenv run format 13 | language: system 14 | types: [python] 15 | - id: python_lint 16 | name: python_lint 17 | entry: pipenv run lint 18 | language: system 19 | types: [python] 20 | - id: python_type_check 21 | name: python_type_check 22 | entry: pipenv run type_check 23 | language: system 24 | types: [python] 25 | - id: python_test 26 | name: python_test 27 | entry: pipenv run test 28 | language: system 29 | types: [python] 30 | verbose: true 31 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # A comma-separated list of package or module names from where C extensions may 4 | # be loaded. Extensions are loading into the active Python interpreter and may 5 | # run arbitrary code 6 | extension-pkg-whitelist= 7 | 8 | # Add files or directories to the blacklist. They should be base names, not 9 | # paths. 10 | ignore=CVS 11 | 12 | # Add files or directories matching the regex patterns to the blacklist. The 13 | # regex matches against base names, not paths. 14 | ignore-patterns=\d{4}.+\.py, 15 | test, 16 | apps.py, 17 | __init__.py, 18 | urls.py, 19 | manage.py, 20 | invalid-envvar-default 21 | 22 | # Python code to execute, usually for sys.path manipulation such as 23 | # pygtk.require(). 24 | #init-hook= 25 | 26 | # Use multiple processes to speed up Pylint. 27 | jobs=0 28 | 29 | # List of plugins (as comma separated values of python modules names) to load, 30 | # usually to register additional checkers. 31 | load-plugins= 32 | 33 | # Pickle collected data for later comparisons. 34 | persistent=yes 35 | 36 | # Specify a configuration file. 37 | #rcfile= 38 | 39 | # When enabled, pylint would attempt to guess common misconfiguration and emit 40 | # user-friendly hints instead of false-positive error messages 41 | suggestion-mode=yes 42 | 43 | # Allow loading of arbitrary C extensions. Extensions are imported into the 44 | # active Python interpreter and may run arbitrary code. 45 | unsafe-load-any-extension=no 46 | 47 | 48 | [MESSAGES CONTROL] 49 | 50 | # Only show warnings with the listed confidence levels. Leave empty to show 51 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 52 | confidence= 53 | 54 | # Disable the message, report, category or checker with the given id(s). You 55 | # can either give multiple identifiers separated by comma (,) or put this 56 | # option multiple times (only on the command line, not in the configuration 57 | # file where it should appear only once).You can also use "--disable=all" to 58 | # disable everything first and then reenable specific checks. For example, if 59 | # you want to run only the similarities checker, you can use "--disable=all 60 | # --enable=similarities". If you want to run only the classes checker, but have 61 | # no Warning level messages displayed, use"--disable=all --enable=classes 62 | # --disable=W" 63 | disable=too-many-arguments, 64 | too-many-instance-attributes, 65 | arguments-differ, 66 | len-as-condition, 67 | missing-docstring, 68 | invalid-envvar-default, 69 | ungrouped-imports, 70 | bad-continuation, 71 | too-many-ancestors, 72 | too-few-public-methods, 73 | no-self-use, 74 | #print-statement, 75 | #parameter-unpacking, 76 | #unpacking-in-except, 77 | #old-raise-syntax, 78 | #backtick, 79 | #long-suffix, 80 | #old-ne-operator, 81 | #old-octal-literal, 82 | #import-star-module-level, 83 | #non-ascii-bytes-literal, 84 | #raw-checker-failed, 85 | #bad-inline-option, 86 | #locally-disabled, 87 | #locally-enabled, 88 | #file-ignored, 89 | #suppressed-message, 90 | #useless-suppression, 91 | #deprecated-pragma, 92 | #apply-builtin, 93 | #basestring-builtin, 94 | #buffer-builtin, 95 | #cmp-builtin, 96 | #coerce-builtin, 97 | #execfile-builtin, 98 | #file-builtin, 99 | #long-builtin, 100 | #raw_input-builtin, 101 | #reduce-builtin, 102 | #standarderror-builtin, 103 | #unicode-builtin, 104 | #xrange-builtin, 105 | #coerce-method, 106 | #delslice-method, 107 | #getslice-method, 108 | #setslice-method, 109 | #no-absolute-import, 110 | #old-division, 111 | #dict-iter-method, 112 | #dict-view-method, 113 | #next-method-called, 114 | #metaclass-assignment, 115 | #indexing-exception, 116 | #raising-string, 117 | #reload-builtin, 118 | #oct-method, 119 | #hex-method, 120 | #nonzero-method, 121 | #cmp-method, 122 | #input-builtin, 123 | #round-builtin, 124 | #intern-builtin, 125 | #unichr-builtin, 126 | #map-builtin-not-iterating, 127 | #zip-builtin-not-iterating, 128 | #range-builtin-not-iterating, 129 | #filter-builtin-not-iterating, 130 | #using-cmp-argument, 131 | #eq-without-hash, 132 | #div-method, 133 | #idiv-method, 134 | #rdiv-method, 135 | #exception-message-attribute, 136 | #invalid-str-codec, 137 | #sys-max-int, 138 | #bad-python3-import, 139 | #deprecated-string-function, 140 | #deprecated-str-translate-call, 141 | #deprecated-itertools-function, 142 | #deprecated-types-field, 143 | #next-method-defined, 144 | #dict-items-not-iterating, 145 | #dict-keys-not-iterating, 146 | #dict-values-not-iterating 147 | 148 | # Enable the message, report, category or checker with the given id(s). You can 149 | # either give multiple identifier separated by comma (,) or put this option 150 | # multiple time (only on the command line, not in the configuration file where 151 | # it should appear only once). See also the "--disable" option for examples. 152 | enable=c-extension-no-member 153 | 154 | 155 | [REPORTS] 156 | 157 | # Python expression which should return a note less than 10 (10 is the highest 158 | # note). You have access to the variables errors warning, statement which 159 | # respectively contain the number of errors / warnings messages and the total 160 | # number of statements analyzed. This is used by the global evaluation report 161 | # (RP0004). 162 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 163 | 164 | # Template used to display messages. This is a python new-style format string 165 | # used to format the message information. See doc for all details 166 | #msg-template= 167 | 168 | # Set the output format. Available formats are text, parseable, colorized, json 169 | # and msvs (visual studio).You can also give a reporter class, eg 170 | # mypackage.mymodule.MyReporterClass. 171 | output-format=text 172 | 173 | # Tells whether to display a full report or only the messages 174 | reports=no 175 | 176 | # Activate the evaluation score. 177 | score=yes 178 | 179 | 180 | [REFACTORING] 181 | 182 | # Maximum number of nested blocks for function / method body 183 | max-nested-blocks=5 184 | 185 | # Complete name of functions that never returns. When checking for 186 | # inconsistent-return-statements if a never returning function is called then 187 | # it will be considered as an explicit return statement and no message will be 188 | # printed. 189 | never-returning-functions=optparse.Values,sys.exit 190 | 191 | 192 | [BASIC] 193 | 194 | # Naming style matching correct argument names 195 | argument-naming-style=snake_case 196 | 197 | # Regular expression matching correct argument names. Overrides argument- 198 | # naming-style 199 | #argument-rgx= 200 | 201 | # Naming style matching correct attribute names 202 | attr-naming-style=snake_case 203 | 204 | # Regular expression matching correct attribute names. Overrides attr-naming- 205 | # style 206 | #attr-rgx= 207 | 208 | # Bad variable names which should always be refused, separated by a comma 209 | bad-names=foo, 210 | bar, 211 | baz, 212 | toto, 213 | tutu, 214 | tata 215 | 216 | # Naming style matching correct class attribute names 217 | class-attribute-naming-style=any 218 | 219 | # Regular expression matching correct class attribute names. Overrides class- 220 | # attribute-naming-style 221 | #class-attribute-rgx= 222 | 223 | # Naming style matching correct class names 224 | class-naming-style=PascalCase 225 | 226 | # Regular expression matching correct class names. Overrides class-naming-style 227 | #class-rgx= 228 | 229 | # Naming style matching correct constant names 230 | const-naming-style=any 231 | 232 | # Regular expression matching correct constant names. Overrides const-naming- 233 | # style 234 | #const-rgx= 235 | 236 | # Minimum line length for functions/classes that require docstrings, shorter 237 | # ones are exempt. 238 | docstring-min-length=5 239 | 240 | # Naming style matching correct function names 241 | function-naming-style=snake_case 242 | 243 | # Regular expression matching correct function names. Overrides function- 244 | # naming-style 245 | #function-rgx= 246 | 247 | # Good variable names which should always be accepted, separated by a comma 248 | good-names=i, 249 | j, 250 | k, 251 | ex, 252 | Run, 253 | _, 254 | db, 255 | r, 256 | x, 257 | y, 258 | e, 259 | f 260 | 261 | # Include a hint for the correct naming format with invalid-name 262 | include-naming-hint=no 263 | 264 | # Naming style matching correct inline iteration names 265 | inlinevar-naming-style=any 266 | 267 | # Regular expression matching correct inline iteration names. Overrides 268 | # inlinevar-naming-style 269 | #inlinevar-rgx= 270 | 271 | # Naming style matching correct method names 272 | method-naming-style=snake_case 273 | 274 | # Regular expression matching correct method names. Overrides method-naming- 275 | # style 276 | #method-rgx= 277 | 278 | # Naming style matching correct module names 279 | module-naming-style=snake_case 280 | 281 | # Regular expression matching correct module names. Overrides module-naming- 282 | # style 283 | #module-rgx= 284 | 285 | # Colon-delimited sets of names that determine each other's naming style when 286 | # the name regexes allow several styles. 287 | name-group= 288 | 289 | # Regular expression which should only match function or class names that do 290 | # not require a docstring. 291 | no-docstring-rgx=^_ 292 | 293 | # List of decorators that produce properties, such as abc.abstractproperty. Add 294 | # to this list to register other decorators that produce valid properties. 295 | property-classes=abc.abstractproperty 296 | 297 | # Naming style matching correct variable names 298 | variable-naming-style=snake_case 299 | 300 | # Regular expression matching correct variable names. Overrides variable- 301 | # naming-style 302 | #variable-rgx= 303 | 304 | 305 | [FORMAT] 306 | 307 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 308 | expected-line-ending-format= 309 | 310 | # Regexp for a line that is allowed to be longer than the limit. 311 | ignore-long-lines=^\s*(# )??$ 312 | 313 | # Number of spaces of indent required inside a hanging or continued line. 314 | indent-after-paren=4 315 | 316 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 317 | # tab). 318 | indent-string=' ' 319 | 320 | # Maximum number of characters on a single line. 321 | max-line-length=79 322 | 323 | # Maximum number of lines in a module 324 | max-module-lines=1000 325 | 326 | # List of optional constructs for which whitespace checking is disabled. `dict- 327 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 328 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 329 | # `empty-line` allows space-only lines. 330 | no-space-check=trailing-comma, 331 | dict-separator 332 | 333 | # Allow the body of a class to be on the same line as the declaration if body 334 | # contains single statement. 335 | single-line-class-stmt=no 336 | 337 | # Allow the body of an if to be on the same line as the test if there is no 338 | # else. 339 | single-line-if-stmt=no 340 | 341 | 342 | [LOGGING] 343 | 344 | # Logging modules to check that the string format arguments are in logging 345 | # function parameter format 346 | logging-modules=logging 347 | 348 | 349 | [MISCELLANEOUS] 350 | 351 | # List of note tags to take in consideration, separated by a comma. 352 | notes=FIXME, 353 | XXX, 354 | TODO 355 | 356 | 357 | [SIMILARITIES] 358 | 359 | # Ignore comments when computing similarities. 360 | ignore-comments=yes 361 | 362 | # Ignore docstrings when computing similarities. 363 | ignore-docstrings=yes 364 | 365 | # Ignore imports when computing similarities. 366 | ignore-imports=no 367 | 368 | # Minimum lines number of a similarity. 369 | min-similarity-lines=4 370 | 371 | 372 | [SPELLING] 373 | 374 | # Limits count of emitted suggestions for spelling mistakes 375 | max-spelling-suggestions=4 376 | 377 | # Spelling dictionary name. Available dictionaries: none. To make it working 378 | # install python-enchant package. 379 | spelling-dict= 380 | 381 | # List of comma separated words that should not be checked. 382 | spelling-ignore-words= 383 | 384 | # A path to a file that contains private dictionary; one word per line. 385 | spelling-private-dict-file= 386 | 387 | # Tells whether to store unknown words to indicated private dictionary in 388 | # --spelling-private-dict-file option instead of raising a message. 389 | spelling-store-unknown-words=no 390 | 391 | 392 | [TYPECHECK] 393 | 394 | # List of decorators that produce context managers, such as 395 | # contextlib.contextmanager. Add to this list to register other decorators that 396 | # produce valid context managers. 397 | contextmanager-decorators=contextlib.contextmanager 398 | 399 | # List of members which are set dynamically and missed by pylint inference 400 | # system, and so shouldn't trigger E1101 when accessed. Python regular 401 | # expressions are accepted. 402 | generated-members= 403 | 404 | # Tells whether missing members accessed in mixin class should be ignored. A 405 | # mixin class is detected if its name ends with "mixin" (case insensitive). 406 | ignore-mixin-members=yes 407 | 408 | # This flag controls whether pylint should warn about no-member and similar 409 | # checks whenever an opaque object is returned when inferring. The inference 410 | # can return multiple potential results while evaluating a Python object, but 411 | # some branches might not be evaluated, which results in partial inference. In 412 | # that case, it might be useful to still emit no-member and other checks for 413 | # the rest of the inferred objects. 414 | ignore-on-opaque-inference=yes 415 | 416 | # List of class names for which member attributes should not be checked (useful 417 | # for classes with dynamically set attributes). This supports the use of 418 | # qualified names. 419 | ignored-classes=optparse.Values,thread._local,_thread._local 420 | 421 | # List of module names for which member attributes should not be checked 422 | # (useful for modules/projects where namespaces are manipulated during runtime 423 | # and thus existing member attributes cannot be deduced by static analysis. It 424 | # supports qualified module names, as well as Unix pattern matching. 425 | ignored-modules= 426 | 427 | # Show a hint with possible names when a member name was not found. The aspect 428 | # of finding the hint is based on edit distance. 429 | missing-member-hint=yes 430 | 431 | # The minimum edit distance a name should have in order to be considered a 432 | # similar match for a missing member name. 433 | missing-member-hint-distance=1 434 | 435 | # The total number of similar names that should be taken in consideration when 436 | # showing a hint for a missing member. 437 | missing-member-max-choices=1 438 | 439 | 440 | [VARIABLES] 441 | 442 | # List of additional names supposed to be defined in builtins. Remember that 443 | # you should avoid to define new builtins when possible. 444 | additional-builtins= 445 | 446 | # Tells whether unused global variables should be treated as a violation. 447 | allow-global-unused-variables=yes 448 | 449 | # List of strings which can identify a callback function by name. A callback 450 | # name must start or end with one of those strings. 451 | callbacks=cb_, 452 | _cb 453 | 454 | # A regular expression matching the name of dummy variables (i.e. expectedly 455 | # not used). 456 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 457 | 458 | # Argument names that match this expression will be ignored. Default to name 459 | # with leading underscore 460 | ignored-argument-names=_.*|^ignored_|^unused_ 461 | 462 | # Tells whether we should check for unused import in __init__ files. 463 | init-import=no 464 | 465 | # List of qualified module names which can have objects that can redefine 466 | # builtins. 467 | redefining-builtins-modules=six.moves,past.builtins,future.builtins 468 | 469 | 470 | [CLASSES] 471 | 472 | # List of method names used to declare (i.e. assign) instance attributes. 473 | defining-attr-methods=__init__, 474 | __new__, 475 | setUp 476 | 477 | # List of member names, which should be excluded from the protected access 478 | # warning. 479 | exclude-protected=_asdict, 480 | _fields, 481 | _replace, 482 | _source, 483 | _make 484 | 485 | # List of valid names for the first argument in a class method. 486 | valid-classmethod-first-arg=cls 487 | 488 | # List of valid names for the first argument in a metaclass class method. 489 | valid-metaclass-classmethod-first-arg=mcs 490 | 491 | 492 | [DESIGN] 493 | 494 | # Maximum number of arguments for function / method 495 | max-args=5 496 | 497 | # Maximum number of attributes for a class (see R0902). 498 | max-attributes=7 499 | 500 | # Maximum number of boolean expressions in a if statement 501 | max-bool-expr=5 502 | 503 | # Maximum number of branch for function / method body 504 | max-branches=12 505 | 506 | # Maximum number of locals for function / method body 507 | max-locals=16 508 | 509 | # Maximum number of parents for a class (see R0901). 510 | max-parents=7 511 | 512 | # Maximum number of public methods for a class (see R0904). 513 | max-public-methods=20 514 | 515 | # Maximum number of return / yield for function / method body 516 | max-returns=6 517 | 518 | # Maximum number of statements in function / method body 519 | max-statements=50 520 | 521 | # Minimum number of public methods for a class (see R0903). 522 | min-public-methods=2 523 | 524 | 525 | [IMPORTS] 526 | 527 | # Allow wildcard imports from modules that define __all__. 528 | allow-wildcard-with-all=no 529 | 530 | # Analyse import fallback blocks. This can be used to support both Python 2 and 531 | # 3 compatible code, which means that the block might have code that exists 532 | # only in one or another interpreter, leading to false positives when analysed. 533 | analyse-fallback-blocks=no 534 | 535 | # Deprecated modules which should not be used, separated by a comma 536 | deprecated-modules=regsub, 537 | TERMIOS, 538 | Bastion, 539 | rexec 540 | 541 | # Create a graph of external dependencies in the given file (report RP0402 must 542 | # not be disabled) 543 | ext-import-graph= 544 | 545 | # Create a graph of every (i.e. internal and external) dependencies in the 546 | # given file (report RP0402 must not be disabled) 547 | import-graph= 548 | 549 | # Create a graph of internal dependencies in the given file (report RP0402 must 550 | # not be disabled) 551 | int-import-graph= 552 | 553 | # Force import order to recognize a module as part of the standard 554 | # compatibility libraries. 555 | known-standard-library= 556 | 557 | # Force import order to recognize a module as part of a third party library. 558 | known-third-party=enchant 559 | 560 | 561 | [EXCEPTIONS] 562 | 563 | # Exceptions that will emit a warning when being caught. Defaults to 564 | # "Exception" 565 | overgeneral-exceptions=Exception 566 | 567 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "3.6" 5 | 6 | env: 7 | - PROJ=${PWD##*/} 8 | 9 | install: 10 | - pip install pipenv 11 | - pipenv install --dev --system 12 | 13 | script: 14 | - pipenv run test 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 shidenggui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | init: 2 | pip install pipenv 3 | pipenv install --dev 4 | pipenv run pre-commit install 5 | @echo && echo use "pipenv shell" to access virtual env 6 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "http://mirrors.aliyun.com/pypi/simple/" 3 | verify_ssl = false 4 | name = "pypi" 5 | 6 | [packages] 7 | six = "*" 8 | requests = "*" 9 | easyutils = "*" 10 | 11 | [dev-packages] 12 | pytest-cov = "*" 13 | pre-commit = "*" 14 | pytest = "*" 15 | pylint = "*" 16 | mypy = "*" 17 | isort = "*" 18 | black = "==18.6b4" 19 | ipython = "*" 20 | better-exceptions = "*" 21 | pylint-django = "*" 22 | bumpversion = "*" 23 | 24 | [requires] 25 | python_version = "3.6" 26 | 27 | [scripts] 28 | sort_imports = "bash -c 'isort \"$@\"; git add -u' --" 29 | format = "bash -c 'black -l 79 \"$@\"; git add -u' --" 30 | lint = "pylint" 31 | type_check = "mypy" 32 | test = "bash -c 'pytest --cov=easyquotation'" 33 | bump = "bash -c 'pipenv lock -r > requirements.txt; git add -u; git commit -m \":star: update requirements.txt\"; bumpversion \"$@\"' --" 34 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "faae4a929e55565ebfed9d8744b0f1765c8a4d6ed4a6e1538846a938830e5942" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.6" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "http://mirrors.aliyun.com/pypi/simple/", 14 | "verify_ssl": false 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "certifi": { 20 | "hashes": [ 21 | "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", 22 | "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" 23 | ], 24 | "version": "==2018.4.16" 25 | }, 26 | "chardet": { 27 | "hashes": [ 28 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 29 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 30 | ], 31 | "version": "==3.0.4" 32 | }, 33 | "cssselect": { 34 | "hashes": [ 35 | "sha256:066d8bc5229af09617e24b3ca4d52f1f9092d9e061931f4184cd572885c23204", 36 | "sha256:3b5103e8789da9e936a68d993b70df732d06b8bb9a337a05ed4eb52c17ef7206" 37 | ], 38 | "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'", 39 | "version": "==1.0.3" 40 | }, 41 | "easyutils": { 42 | "hashes": [ 43 | "sha256:45b46748e20dd3c0e840fa9c1fa7d7f3dc295e58a81796d10329957c20b7f20a" 44 | ], 45 | "index": "pypi", 46 | "version": "==0.1.7" 47 | }, 48 | "idna": { 49 | "hashes": [ 50 | "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", 51 | "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" 52 | ], 53 | "version": "==2.7" 54 | }, 55 | "lxml": { 56 | "hashes": [ 57 | "sha256:0941f4313208c07734410414d8308812b044fd3fb98573454e3d3a0d2e201f3d", 58 | "sha256:0b18890aa5730f9d847bc5469e8820f782d72af9985a15a7552109a86b01c113", 59 | "sha256:21f427945f612ac75576632b1bb8c21233393c961f2da890d7be3927a4b6085f", 60 | "sha256:24cf6f622a4d49851afcf63ac4f0f3419754d4e98a7a548ab48dd03c635d9bd3", 61 | "sha256:2dc6705486b8abee1af9e2a3761e30a3cb19e8276f20ca7e137ee6611b93707c", 62 | "sha256:2e43b2e5b7d2b9abe6e0301eef2c2c122ab45152b968910eae68bdee2c4cfae0", 63 | "sha256:329a6d8b6d36f7d6f8b6c6a1db3b2c40f7e30a19d3caf62023c9d6a677c1b5e1", 64 | "sha256:423cde55430a348bda6f1021faad7235c2a95a6bdb749e34824e5758f755817a", 65 | "sha256:4651ea05939374cfb5fe87aab5271ed38c31ea47997e17ec3834b75b94bd9f15", 66 | "sha256:4be3bbfb2968d7da6e5c2cd4104fc5ec1caf9c0794f6cae724da5a53b4d9f5a3", 67 | "sha256:622f7e40faef13d232fb52003661f2764ce6cdef3edb0a59af7c1559e4cc36d1", 68 | "sha256:664dfd4384d886b239ef0d7ee5cff2b463831079d250528b10e394a322f141f9", 69 | "sha256:697c0f58ac637b11991a1bc92e07c34da4a72e2eda34d317d2c1c47e2f24c1b3", 70 | "sha256:6ec908b4c8a4faa7fe1a0080768e2ce733f268b287dfefb723273fb34141475f", 71 | "sha256:7ec3fe795582b75bb49bb1685ffc462dbe38d74312dac07ce386671a28b5316b", 72 | "sha256:8c39babd923c431dcf1e5874c0f778d3a5c745a62c3a9b6bd755efd489ee8a1d", 73 | "sha256:949ca5bc56d6cb73d956f4862ba06ad3c5d2808eac76304284f53ae0c8b2334a", 74 | "sha256:9f0daddeefb0791a600e6195441910bdf01eac470be596b9467e6122b51239a6", 75 | "sha256:a359893b01c30e949eae0e8a85671a593364c9f0b8162afe0cb97317af0953bf", 76 | "sha256:ad5d5d8efed59e6b1d4c50c1eac59fb6ecec91b2073676af1e15fc4d43e9b6c5", 77 | "sha256:bc1a36f95a6b3667c09b34995fc3a46a82e4cf0dc3e7ab281e4c77b15bd7af05", 78 | "sha256:be37b3f55b6d7d923f43bf74c356fc1878eb36e28505f38e198cb432c19c7b1a", 79 | "sha256:c45bca5e544eb75f7500ffd730df72922eb878a2f0213b0dc5a5f357ded3a85d", 80 | "sha256:ccee7ebbb4735ebc341d347fca9ee09f2fa6c0580528c1414bc4e1d31372835c", 81 | "sha256:dc62c0840b2fc7753550b40405532a3e125c0d3761f34af948873393aa688160", 82 | "sha256:f7d9d5aa1c7e54167f1a3cba36b5c52c7c540f30952c9bd7d9302a1eda318424" 83 | ], 84 | "version": "==4.2.3" 85 | }, 86 | "pyquery": { 87 | "hashes": [ 88 | "sha256:07987c2ed2aed5cba29ff18af95e56e9eb04a2249f42ce47bddfb37f487229a3", 89 | "sha256:4771db76bd14352eba006463656aef990a0147a0eeaf094725097acfa90442bf" 90 | ], 91 | "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*'", 92 | "version": "==1.4.0" 93 | }, 94 | "requests": { 95 | "hashes": [ 96 | "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", 97 | "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" 98 | ], 99 | "index": "pypi", 100 | "version": "==2.19.1" 101 | }, 102 | "six": { 103 | "hashes": [ 104 | "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", 105 | "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" 106 | ], 107 | "index": "pypi", 108 | "version": "==1.11.0" 109 | }, 110 | "urllib3": { 111 | "hashes": [ 112 | "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", 113 | "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" 114 | ], 115 | "markers": "python_version != '3.2.*' and python_version < '4' and python_version != '3.3.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.1.*'", 116 | "version": "==1.23" 117 | } 118 | }, 119 | "develop": { 120 | "appdirs": { 121 | "hashes": [ 122 | "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", 123 | "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" 124 | ], 125 | "version": "==1.4.3" 126 | }, 127 | "appnope": { 128 | "hashes": [ 129 | "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", 130 | "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71" 131 | ], 132 | "markers": "sys_platform == 'darwin'", 133 | "version": "==0.1.0" 134 | }, 135 | "aspy.yaml": { 136 | "hashes": [ 137 | "sha256:04d26279513618f1024e1aba46471db870b3b33aef204c2d09bcf93bea9ba13f", 138 | "sha256:0a77e23fafe7b242068ffc0252cee130d3e509040908fc678d9d1060e7494baa" 139 | ], 140 | "version": "==1.1.1" 141 | }, 142 | "astroid": { 143 | "hashes": [ 144 | "sha256:0a0c484279a5f08c9bcedd6fa9b42e378866a7dcc695206b92d59dc9f2d9760d", 145 | "sha256:218e36cf8d98a42f16214e8670819ce307fa707d1dcf7f9af84c7aede1febc7f" 146 | ], 147 | "version": "==2.0.1" 148 | }, 149 | "atomicwrites": { 150 | "hashes": [ 151 | "sha256:240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585", 152 | "sha256:a24da68318b08ac9c9c45029f4a10371ab5b20e4226738e150e6e7c571630ae6" 153 | ], 154 | "version": "==1.1.5" 155 | }, 156 | "attrs": { 157 | "hashes": [ 158 | "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", 159 | "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b" 160 | ], 161 | "version": "==18.1.0" 162 | }, 163 | "backcall": { 164 | "hashes": [ 165 | "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", 166 | "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2" 167 | ], 168 | "version": "==0.1.0" 169 | }, 170 | "better-exceptions": { 171 | "hashes": [ 172 | "sha256:0a73efef96b48f867ea980227ac3b00d36a92754e6d316ad2ee472f136014580" 173 | ], 174 | "index": "pypi", 175 | "version": "==0.2.1" 176 | }, 177 | "black": { 178 | "hashes": [ 179 | "sha256:22158b89c1a6b4eb333a1e65e791a3f8b998cf3b11ae094adb2570f31f769a44", 180 | "sha256:4b475bbd528acce094c503a3d2dbc2d05a4075f6d0ef7d9e7514518e14cc5191" 181 | ], 182 | "index": "pypi", 183 | "version": "==18.6b4" 184 | }, 185 | "bumpversion": { 186 | "hashes": [ 187 | "sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e", 188 | "sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57" 189 | ], 190 | "index": "pypi", 191 | "version": "==0.5.3" 192 | }, 193 | "cached-property": { 194 | "hashes": [ 195 | "sha256:630fdbf0f4ac7d371aa866016eba1c3ac43e9032246748d4994e67cb05f99bc4", 196 | "sha256:f1f9028757dc40b4cb0fd2234bd7b61a302d7b84c683cb8c2c529238a24b8938" 197 | ], 198 | "version": "==1.4.3" 199 | }, 200 | "cfgv": { 201 | "hashes": [ 202 | "sha256:73f48a752bd7aab103c4b882d6596c6360b7aa63b34073dd2c35c7b4b8f93010", 203 | "sha256:d1791caa9ff5c0c7bce80e7ecc1921752a2eb7c2463a08ed9b6c96b85a2f75aa" 204 | ], 205 | "version": "==1.1.0" 206 | }, 207 | "click": { 208 | "hashes": [ 209 | "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", 210 | "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" 211 | ], 212 | "version": "==6.7" 213 | }, 214 | "coverage": { 215 | "hashes": [ 216 | "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", 217 | "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", 218 | "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", 219 | "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", 220 | "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", 221 | "sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", 222 | "sha256:2a5b73210bad5279ddb558d9a2bfedc7f4bf6ad7f3c988641d83c40293deaec1", 223 | "sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", 224 | "sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", 225 | "sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", 226 | "sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", 227 | "sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", 228 | "sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", 229 | "sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", 230 | "sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", 231 | "sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", 232 | "sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", 233 | "sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", 234 | "sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", 235 | "sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", 236 | "sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", 237 | "sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", 238 | "sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", 239 | "sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", 240 | "sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", 241 | "sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", 242 | "sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", 243 | "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", 244 | "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", 245 | "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", 246 | "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" 247 | ], 248 | "markers": "python_version < '4' and python_version >= '2.6' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*'", 249 | "version": "==4.5.1" 250 | }, 251 | "decorator": { 252 | "hashes": [ 253 | "sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82", 254 | "sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c" 255 | ], 256 | "version": "==4.3.0" 257 | }, 258 | "identify": { 259 | "hashes": [ 260 | "sha256:49845e70fc6b1ec3694ab930a2c558912d7de24548eebcd448f65567dc757c43", 261 | "sha256:68daab16a3db364fa204591f97dc40bfffd1a7739f27788a4895b4d8fd3516e5" 262 | ], 263 | "version": "==1.1.4" 264 | }, 265 | "ipython": { 266 | "hashes": [ 267 | "sha256:a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f", 268 | "sha256:eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c" 269 | ], 270 | "index": "pypi", 271 | "version": "==6.4.0" 272 | }, 273 | "ipython-genutils": { 274 | "hashes": [ 275 | "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", 276 | "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" 277 | ], 278 | "version": "==0.2.0" 279 | }, 280 | "isort": { 281 | "hashes": [ 282 | "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", 283 | "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", 284 | "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" 285 | ], 286 | "index": "pypi", 287 | "version": "==4.3.4" 288 | }, 289 | "jedi": { 290 | "hashes": [ 291 | "sha256:b409ed0f6913a701ed474a614a3bb46e6953639033e31f769ca7581da5bd1ec1", 292 | "sha256:c254b135fb39ad76e78d4d8f92765ebc9bf92cbc76f49e97ade1d5f5121e1f6f" 293 | ], 294 | "version": "==0.12.1" 295 | }, 296 | "lazy-object-proxy": { 297 | "hashes": [ 298 | "sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", 299 | "sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", 300 | "sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", 301 | "sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", 302 | "sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", 303 | "sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", 304 | "sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", 305 | "sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", 306 | "sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", 307 | "sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", 308 | "sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", 309 | "sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", 310 | "sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", 311 | "sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", 312 | "sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", 313 | "sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", 314 | "sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", 315 | "sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", 316 | "sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", 317 | "sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", 318 | "sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", 319 | "sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", 320 | "sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", 321 | "sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", 322 | "sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", 323 | "sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", 324 | "sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", 325 | "sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", 326 | "sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" 327 | ], 328 | "version": "==1.3.1" 329 | }, 330 | "mccabe": { 331 | "hashes": [ 332 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", 333 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" 334 | ], 335 | "version": "==0.6.1" 336 | }, 337 | "more-itertools": { 338 | "hashes": [ 339 | "sha256:2b6b9893337bfd9166bee6a62c2b0c9fe7735dcf85948b387ec8cba30e85d8e8", 340 | "sha256:6703844a52d3588f951883005efcf555e49566a48afd4db4e965d69b883980d3", 341 | "sha256:a18d870ef2ffca2b8463c0070ad17b5978056f403fb64e3f15fe62a52db21cc0" 342 | ], 343 | "version": "==4.2.0" 344 | }, 345 | "mypy": { 346 | "hashes": [ 347 | "sha256:673ea75fb750289b7d1da1331c125dc62fc1c3a8db9129bb372ae7b7d5bf300a", 348 | "sha256:c770605a579fdd4a014e9f0a34b6c7a36ce69b08100ff728e96e27445cef3b3c" 349 | ], 350 | "index": "pypi", 351 | "version": "==0.620" 352 | }, 353 | "nodeenv": { 354 | "hashes": [ 355 | "sha256:aa040ab5189bae17d272175609010be6c5b589ec4b8dbd832cc50c9e9cb7496f" 356 | ], 357 | "version": "==1.3.2" 358 | }, 359 | "parso": { 360 | "hashes": [ 361 | "sha256:35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2", 362 | "sha256:895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24" 363 | ], 364 | "version": "==0.3.1" 365 | }, 366 | "pexpect": { 367 | "hashes": [ 368 | "sha256:2a8e88259839571d1251d278476f3eec5db26deb73a70be5ed5dc5435e418aba", 369 | "sha256:3fbd41d4caf27fa4a377bfd16fef87271099463e6fa73e92a52f92dfee5d425b" 370 | ], 371 | "markers": "sys_platform != 'win32'", 372 | "version": "==4.6.0" 373 | }, 374 | "pickleshare": { 375 | "hashes": [ 376 | "sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b", 377 | "sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5" 378 | ], 379 | "version": "==0.7.4" 380 | }, 381 | "pluggy": { 382 | "hashes": [ 383 | "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", 384 | "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", 385 | "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" 386 | ], 387 | "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*'", 388 | "version": "==0.6.0" 389 | }, 390 | "pre-commit": { 391 | "hashes": [ 392 | "sha256:99cb6313a8ea7d88871aa2875a12d3c3a7636edf8ce4634b056328966682c8ce", 393 | "sha256:c71e6cf84e812226f8dadbe346b5e6d6728fa65a364bbfe7624b219a18950540" 394 | ], 395 | "index": "pypi", 396 | "version": "==1.10.4" 397 | }, 398 | "prompt-toolkit": { 399 | "hashes": [ 400 | "sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381", 401 | "sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4", 402 | "sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917" 403 | ], 404 | "version": "==1.0.15" 405 | }, 406 | "ptyprocess": { 407 | "hashes": [ 408 | "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", 409 | "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" 410 | ], 411 | "version": "==0.6.0" 412 | }, 413 | "py": { 414 | "hashes": [ 415 | "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", 416 | "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" 417 | ], 418 | "markers": "python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*'", 419 | "version": "==1.5.4" 420 | }, 421 | "pygments": { 422 | "hashes": [ 423 | "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", 424 | "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" 425 | ], 426 | "version": "==2.2.0" 427 | }, 428 | "pylint": { 429 | "hashes": [ 430 | "sha256:2c90a24bee8fae22ac98061c896e61f45c5b73c2e0511a4bf53f99ba56e90434", 431 | "sha256:454532779425098969b8f54ab0f056000b883909f69d05905ea114df886e3251" 432 | ], 433 | "index": "pypi", 434 | "version": "==2.0.1" 435 | }, 436 | "pylint-django": { 437 | "hashes": [ 438 | "sha256:5c5a20c443b4e70fdc8c47e42cff8ce79c953954e918f8e559f6e1d05a971585", 439 | "sha256:70f2b5397aa2468373fcf87d64a700b359050e905e56e2dbaf954e6edb04c593" 440 | ], 441 | "index": "pypi", 442 | "version": "==2.0" 443 | }, 444 | "pylint-plugin-utils": { 445 | "hashes": [ 446 | "sha256:8ad25a82bcce390d1d6b7c006c123e0cb18051839c9df7b8bdb7823c53fe676e" 447 | ], 448 | "version": "==0.4" 449 | }, 450 | "pytest": { 451 | "hashes": [ 452 | "sha256:341ec10361b64a24accaec3c7ba5f7d5ee1ca4cebea30f76fad3dd12db9f0541", 453 | "sha256:952c0389db115437f966c4c2079ae9d54714b9455190e56acebe14e8c38a7efa" 454 | ], 455 | "index": "pypi", 456 | "version": "==3.6.4" 457 | }, 458 | "pytest-cov": { 459 | "hashes": [ 460 | "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d", 461 | "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec" 462 | ], 463 | "index": "pypi", 464 | "version": "==2.5.1" 465 | }, 466 | "pyyaml": { 467 | "hashes": [ 468 | "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", 469 | "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", 470 | "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", 471 | "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", 472 | "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", 473 | "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", 474 | "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", 475 | "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", 476 | "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", 477 | "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", 478 | "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" 479 | ], 480 | "version": "==3.13" 481 | }, 482 | "simplegeneric": { 483 | "hashes": [ 484 | "sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173" 485 | ], 486 | "version": "==0.8.1" 487 | }, 488 | "six": { 489 | "hashes": [ 490 | "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", 491 | "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" 492 | ], 493 | "index": "pypi", 494 | "version": "==1.11.0" 495 | }, 496 | "toml": { 497 | "hashes": [ 498 | "sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d" 499 | ], 500 | "version": "==0.9.4" 501 | }, 502 | "traitlets": { 503 | "hashes": [ 504 | "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", 505 | "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9" 506 | ], 507 | "version": "==4.3.2" 508 | }, 509 | "typed-ast": { 510 | "hashes": [ 511 | "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", 512 | "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", 513 | "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", 514 | "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", 515 | "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", 516 | "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", 517 | "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", 518 | "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", 519 | "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", 520 | "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", 521 | "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", 522 | "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", 523 | "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", 524 | "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", 525 | "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", 526 | "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", 527 | "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", 528 | "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", 529 | "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", 530 | "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", 531 | "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", 532 | "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", 533 | "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" 534 | ], 535 | "markers": "python_version < '3.7' and implementation_name == 'cpython'", 536 | "version": "==1.1.0" 537 | }, 538 | "virtualenv": { 539 | "hashes": [ 540 | "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669", 541 | "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752" 542 | ], 543 | "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.0.*'", 544 | "version": "==16.0.0" 545 | }, 546 | "wcwidth": { 547 | "hashes": [ 548 | "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", 549 | "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" 550 | ], 551 | "version": "==0.1.7" 552 | }, 553 | "wrapt": { 554 | "hashes": [ 555 | "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" 556 | ], 557 | "version": "==1.10.11" 558 | } 559 | } 560 | } 561 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easyquotation 2 | 3 | [![Package](https://img.shields.io/pypi/v/easyquotation.svg)](https://pypi.python.org/pypi/easyquotation) 4 | [![Travis](https://img.shields.io/travis/shidenggui/easyquotation.svg)](https://travis-ci.org/shidenggui/easyquotation) 5 | [![License](https://img.shields.io/github/license/shidenggui/easyquotation.svg)](https://github.com/shidenggui/easyquotation/blob/master/LICENSE) 6 | 7 | 8 | 快速获取新浪/腾讯的全市场行情, 网络正常的情况下只需要 `200+ms` 9 | 10 | ### 前言 11 | * 获取新浪的免费实时行情 12 | * 获取腾讯财经的免费实时行情 13 | * 获取集思路的分级基金数据 14 | * 有兴趣的可以加群 `556050652` 一起讨论 15 | * 捐助: 16 | 17 | ![微信](http://7xqo8v.com1.z0.glb.clouddn.com/wx.png?imageView2/1/w/300/h/300) ![支付宝](http://7xqo8v.com1.z0.glb.clouddn.com/zhifubao2.png?imageView2/1/w/300/h/300) 18 | 19 | 20 | ## 公众号 21 | 22 | 扫码关注“易量化”的微信公众号,不定时更新一些个人文章及与大家交流 23 | 24 | ![](http://7xqo8v.com1.z0.glb.clouddn.com/easy_quant_qrcode.jpg?imageView2/1/w/300/h/300) 25 | 26 | **开发环境** : `Ubuntu 16.04` / `Python 3.5` 27 | 28 | ### requirements 29 | 30 | > Python 3.5+ 31 | 32 | > pip install -r requirements.txt 33 | 34 | ### 安装 35 | 36 | ```python 37 | pip install easyquotation 38 | ``` 39 | 40 | 也可以下载源码,然后安装 41 | 42 | ```python 43 | python setup.py install 44 | ``` 45 | 46 | #### 升级 47 | 48 | ```python 49 | pip install easyquotation --upgrade 50 | ``` 51 | 52 | ### 用法 53 | 54 | #### 引入: 55 | 56 | ```python 57 | import easyquotation 58 | ``` 59 | 60 | #### 选择行情 61 | 62 | ```python 63 | quotation = easyquotation.use('sina') # 新浪 ['sina'] 腾讯 ['tencent', 'qq'] 64 | ``` 65 | 66 | #### 获取所有股票行情 67 | 68 | ```python 69 | quotation.market_snapshot(prefix=True) # prefix 参数指定返回的行情字典中的股票代码 key 是否带 sz/sh 前缀 70 | ``` 71 | 72 | **return** 73 | 74 | ```python 75 | {'sh000159': {'name': '国际实业', # 股票名 76 | 'buy': 8.87, # 竞买价 77 | 'sell': 8.88, # 竞卖价 78 | 'now': 8.88, # 现价 79 | 'open': 8.99, # 开盘价 80 | 'close': 8.96, # 昨日收盘价 81 | 'high': 9.15, # 今日最高价 82 | 'low': 8.83, # 今日最低价 83 | 'turnover': 22545048, # 交易股数 84 | 'volume': 202704887.74, # 交易金额 85 | 'ask1': 8.88, # 卖一价 86 | 'ask1_volume': 111900, # 卖一量 87 | 'ask2': 8.89, 88 | 'ask2_volume': 54700, 89 | 'bid1': 8.87, # 买一价 90 | 'bid1_volume': 21800, # 买一量 91 | ... 92 | 'bid2': 8.86, 93 | 'bid2_volume': 78400, 94 | 'date': '2016-02-19', 95 | 'time': '14:30:00', 96 | ...}, 97 | ...... 98 | } 99 | ``` 100 | 101 | ##### 单只股票 102 | 103 | ``` 104 | quotation.real('162411') # 支持直接指定前缀,如 'sh000001' 105 | ``` 106 | 107 | ##### 多只股票 108 | 109 | ``` 110 | quotation.stocks(['000001', '162411']) 111 | ``` 112 | 113 | ##### 同时获取指数和行情 114 | 115 | ``` 116 | quotation.stocks(['sh000001', 'sz000001'], prefix=True) 117 | ``` 118 | 119 | #### 更新股票代码 120 | 121 | ``` 122 | easyquotation.update_stock_codes() 123 | ``` 124 | 125 | 126 | #### 选择 [jsl](https://www.jisilu.cn)(集思路) 行情 127 | 128 | ``` 129 | quotation = easyquotation.use('jsl') # ['jsl'] 130 | ``` 131 | 132 | ##### 获取分级基金信息 133 | 134 | ``` 135 | quotation.funda() # 参数可选择利率、折价率、交易量、有无下折、是否永续来过滤 136 | 137 | quotation.fundb() # 参数如上 138 | ``` 139 | 140 | 对应的分级 A 数据 141 | 142 | **return** 143 | 144 | ``` 145 | { 150020: 146 | {'abrate': '5:5', 147 | 'calc_info': None, 148 | 'coupon_descr': '+3.0%', 149 | 'coupon_descr_s': '+3.0%', 150 | 'fund_descr': '每年第一个工作日定折,无下折,A不参与上折,净值<1元无定折', 151 | 'funda_amount': 178823, 152 | 'funda_amount_increase': '0', 153 | 'funda_amount_increase_rt': '0.00%', 154 | 'funda_base_est_dis_rt': '2.27%', 155 | 'funda_base_est_dis_rt_t1': '2.27%', 156 | 'funda_base_est_dis_rt_t2': '-0.34%', 157 | 'funda_base_est_dis_rt_tip': '', 158 | 'funda_base_fund_id': '163109', 159 | 'funda_coupon': '5.75', 160 | 'funda_coupon_next': '4.75', 161 | 'funda_current_price': '0.783', 162 | 'funda_discount_rt': '24.75%', 163 | 'funda_id': '150022', 164 | 'funda_increase_rt': '0.00%', 165 | 'funda_index_id': '399001', 166 | 'funda_index_increase_rt': '0.00%', 167 | 'funda_index_name': '深证成指', 168 | 'funda_left_year': '永续', 169 | 'funda_lower_recalc_rt': '1.82%', 170 | 'funda_name': '深成指A', 171 | 'funda_nav_dt': '2015-09-14', 172 | 'funda_profit_rt': '7.74%', 173 | 'funda_profit_rt_next': '6.424%', 174 | 'funda_value': '1.0405', 175 | 'funda_volume': '0.00', 176 | 'fundb_upper_recalc_rt': '244.35%', 177 | 'fundb_upper_recalc_rt_info': '深成指A不参与上折', 178 | 'last_time': '09:18:22', 179 | 'left_recalc_year': '0.30411', 180 | 'lower_recalc_profit_rt': '-', 181 | 'next_recalc_dt': '2016-01-04', 182 | 'owned': 0, 183 | 'status_cd': 'N'}>'}} 184 | ``` 185 | 186 | ##### 分级基金套利接口 187 | 188 | ``` 189 | quotation.fundarb(jsl_username, jsl_password, avolume=100, bvolume=100, ptype='price') 190 | ``` 191 | 192 | ``` 193 | jsl_username: 集思录用户名 194 | jsl_password: 集思路登录密码 195 | avolume: A成交额,单位百万 196 | bvolume: B成交额,单位百万 197 | ptype: 溢价计算方式,price=现价,buy=买一,sell=卖一 198 | ``` 199 | 200 | **return** 201 | ``` 202 | { 203 | "165511":{ 204 | 'base_fund_id': '165511', # 母基金代码 205 | 'AB_price': '现价A/B : 1.008/1.329', 206 | 'a_profit_rt_next': '4.705', 207 | 'a_ratio': 4, 208 | 'abrate': '4:6', 209 | 'apply_fee': '0', 210 | 'apply_fee_tip': '0', 211 | 'apply_sell': '-0.59', 212 | 'asset_ratio': '95%', 213 | 'asset_ratio_last': '99%', 214 | 'asset_ratio_num': '95.00', 215 | 'b_est_val': '1.340', 216 | 'b_gangan': '1.502', 217 | 'b_ratio': 6, 218 | 'base_est_dis_rt': '-0.56%', 219 | 'base_est_val': '1.2073', 220 | 'base_fund_nm': '信诚500', 221 | 'base_lower_recalc_rt': '54.15%', 222 | 'base_nav': '1.1970', 223 | 'base_nav_dt': '2016-04-13', 224 | 'buy1A': '1.007', 225 | 'buy1B': '1.329', 226 | 'buy1_amountA': '0.201', 227 | 'buy1_amountB': '7.123', 228 | 'buy_redeem': '-0.51', 229 | 'calc_info': None, 230 | 'coupon': '0.00%', 231 | 'coupon_next': '4.700', 232 | 'est_dis_rt': '-0.55%', 233 | 'est_time': '2016-04-14 15:10:05', 234 | 'fundA_amount': '6667', 235 | 'fundA_amount_increase': '-51', 236 | 'fundA_amount_increase_rt': '-0.76%', 237 | 'fundA_amount_tip': '2016-04-14 A类总份额6667.000万份,份额增长-0.76%', 238 | 'fundA_id': '150028', 239 | 'fundA_last_dt': '2016-04-14', 240 | 'fundA_last_time': '14:57:02', 241 | 'fundA_nav': '1.0090', 242 | 'fundA_nav_dt': '2016-04-13', 243 | 'fundA_nm': '中证500A', 244 | 'fundA_stock_volume': '28.2446', 245 | 'fundA_stock_volume_tip': 'A类总份额6667.000万份, 成交28万份', 246 | 'fundA_turnover_rt': '0.42%', 247 | 'fundA_volume': '28.46', 248 | 'fundB_amount': 10000.5, 249 | 'fundB_amount_increase': '-76', 250 | 'fundB_amount_tip': '2016-04-14 B类总份额10000万份,份额增长-0.76%', 251 | 'fundB_id': '150029', 252 | 'fundB_last_dt': '2016-04-14', 253 | 'fundB_last_time': '15:00:27', 254 | 'fundB_nav': '1.3220', 255 | 'fundB_nav_dt': '2016-04-13', 256 | 'fundB_nm': '中证500B', 257 | 'fundB_stock_volume': '255.5280', 258 | 'fundB_stock_volume_tip': 'B类总份额10000万份, 成交256万份', 259 | 'fundB_turnover_rt': '2.56%', 260 | 'fundB_volume': '337.24', 261 | 'fund_company_nm': '信诚基金', 262 | 'funda_name_tip': '下期利率:4.70,修正收益率:4.71%', 263 | 'idx_incr_rt': '0.91%', 264 | 'increase_rtA': '-0.10%', 265 | 'increase_rtB': '1.06%', 266 | 'index_id': '399905', 267 | 'index_nm': '中证 500', 268 | 'is_est_val': 1, 269 | 'is_last_nav': 1, 270 | 'lower_recalc_rt': '54.15', 271 | 'maturity_dt': '-', 272 | 'merge_price': '1.2006', 273 | 'min_apply_amount': None, 274 | 'notes': 'http://www.xcfunds.com/funds_2012/165511/fundinfor.shtml\r\n', 275 | 'ownedA': 0, 276 | 'ownedM': 1, 277 | 'priceA': '1.008', 278 | 'priceB': '1.329', 279 | 'real_idx_increase_rt': '0.91', 280 | 'recalc_to': None, 281 | 'redeem_fee': '0.5%', 282 | 'redeem_fee_tip': '0.5%', 283 | 'sell1A': '1.008', 284 | 'sell1B': '1.330', 285 | 'sell1_amountA': '7.132', 286 | 'sell1_amountB': '16.820', 287 | 'status_cd': 'N' 288 | } 289 | } 290 | ``` 291 | 292 | ##### 指数ETF查询接口 293 | 294 | **TIP :** 尚未包含黄金ETF和货币ETF 295 | 296 | *[集思录ETF源网页](https://www.jisilu.cn/data/etf/#tlink_2)* 297 | 298 | ``` 299 | quotation.etfindex(index_id="", min_volume=0, max_discount=None, min_discount=None) 300 | ``` 301 | 302 | **return** 303 | 304 | ``` 305 | { 306 | "510050": { 307 | "fund_id": "510050", # 代码 308 | "fund_nm": "50ETF", # 名称 309 | "price": "2.066", # 现价 310 | "increase_rt": "0.34%", # 涨幅 311 | "volume": "71290.96", # 成交额(万元) 312 | "index_nm": "上证50", # 指数 313 | "pe": "9.038", # 指数PE 314 | "pb": "1.151", # 指数PB 315 | "index_increase_rt": "0.45%", # 指数涨幅 316 | "estimate_value": "2.0733", # 估值 317 | "fund_nav": "2.0730", # 净值 318 | "nav_dt": "2016-03-11", # 净值日期 319 | "discount_rt": "-0.34%", # 溢价率 320 | "creation_unit": "90", # 最小申赎单位(万份) 321 | "amount": "1315800", # 份额 322 | "unit_total": "271.84", # 规模(亿元) 323 | "index_id": "000016", # 指数代码 324 | "last_time": "15:00:00", # 价格最后时间(未确定) 325 | "last_est_time": "23:50:02", # 估值最后时间(未确定) 326 | } 327 | } 328 | ``` 329 | 330 | 331 | ##### 分数图 332 | 333 | 334 | *[腾讯分时图地址](http://data.gtimg.cn/flashdata/hushen/minute/sz000001.js)* 335 | 336 | ```python 337 | 338 | quotation = easyquotation.use("timekline") 339 | data = quotation.real(['603828'], prefix=True) 340 | 341 | ``` 342 | 343 | **return** 344 | 345 | ``` 346 | { 347 | 'sh603828': { 348 | 'date': '170721', #日期 349 | 'time_data': { 350 | '201707210930': ['0930', '19.42', '61'], # [时间, 当前价, 上一分钟到这一分钟之间的成交数量] 351 | '201707210931': ['0931', '19.42','122'], 352 | '201707210932': ['0932', '19.43', '123'], 353 | '201707210933': ['0933', '19.48', '125'], 354 | '201707210934': ['0934', '19.49', '133'], 355 | '201707210935': ['0935', '19.48', '161'], 356 | ... 357 | } 358 | } 359 | ``` 360 | 361 | ##### 港股日k线图 362 | *[腾讯日k线图](http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk00700,day,,,350,qfq&r=0.7773272375526847)* 363 | 364 | ```python 365 | 366 | import easyquotation 367 | quotation = easyquotation.use("daykline") 368 | data = quotation.real(['00001','00700']) 369 | print(data) 370 | 371 | ``` 372 | *return* 373 | ``` 374 | { 375 | '00001': [ 376 | ['2017-10-09', '352.00', '349.00', '353.00', '348.60', '13455864.00'], # [日期, 今开, 今收, 最高, 最低, 成交量 ] 377 | ['2017-10-10', '350.80', '351.20', '352.60', '349.80', '10088970.00'], 378 | ] 379 | '00700':[ 380 | 381 | ] 382 | } 383 | } 384 | ``` 385 | 386 | ##### 腾讯港股时时行情 387 | *[腾讯控股时时行情](http://sqt.gtimg.cn/utf8/q=r_hk00700)* 388 | ```python 389 | 390 | import easyquotation 391 | quotation = easyquotation.use("hkquote") 392 | data = quotation.real(['00001','00700']) 393 | print(data) 394 | ``` 395 | 396 | ``` 397 | { 398 | '00001': 399 | { 400 | 'stock_code': '00001', # 股票代码 401 | 'lotSize': '"100', # 每手数量 402 | 'name': '长和', # 股票名称 403 | 'price': '97.20', # 股票当前价格 404 | 'lastPrice': '97.75', # 股票昨天收盘价格 405 | 'openPrice': '97.75', # 股票今天开盘价格 406 | 'amount': '1641463.0', # 股票成交量 407 | 'time': '2017/11/29 15:38:58', # 当前时间 408 | 'high': '98.05', # 当天最高价格 409 | 'low': '97.15' # 当天最低价格 410 | }, 411 | '00700': 412 | { 413 | 'stock_code': '00700', 414 | 'lotSize': '"100', 415 | 'name': '腾讯控股', 416 | 'price': '413.20', 417 | 'lastPrice': '419.20', 418 | 'openPrice': '422.20', 419 | 'amount': '21351010.0', 420 | 'time': '2017/11/29 15:39:01', 421 | 'high': '422.80', 422 | 'low': '412.40' 423 | } 424 | } 425 | ``` 426 | 427 | ### 开发指南 428 | 429 | #### 初始化环境 430 | 431 | 进入项目目录后运行 432 | 433 | ``` 434 | make init 435 | ``` 436 | 437 | 提交代码时通过所有 `hooks` 检查即可 438 | -------------------------------------------------------------------------------- /easyquotation/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | from .api import * 3 | from .helpers import get_stock_codes, update_stock_codes 4 | 5 | __version__ = "0.5.13" 6 | __author__ = "shidenggui" 7 | -------------------------------------------------------------------------------- /easyquotation/api.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | 3 | from . import boc, daykline, hkqoute, jsl, sina, tencent, timekline 4 | 5 | 6 | # pylint: disable=too-many-return-statements 7 | def use(source): 8 | if source in ["sina"]: 9 | return sina.Sina() 10 | if source in ["jsl"]: 11 | return jsl.Jsl() 12 | if source in ["qq", "tencent"]: 13 | return tencent.Tencent() 14 | if source in ["boc"]: 15 | return boc.Boc() 16 | if source in ["timekline"]: 17 | return timekline.TimeKline() 18 | if source in ["daykline"]: 19 | return daykline.DayKline() 20 | if source in ["hkquote"]: 21 | return hkqoute.HKQuote() 22 | raise NotImplementedError 23 | -------------------------------------------------------------------------------- /easyquotation/basequotation.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import abc 3 | import json 4 | import multiprocessing.pool 5 | import warnings 6 | 7 | import easyutils 8 | import requests 9 | 10 | from . import helpers 11 | 12 | 13 | class BaseQuotation(metaclass=abc.ABCMeta): 14 | """行情获取基类""" 15 | 16 | max_num = 800 # 每次请求的最大股票数 17 | 18 | @property 19 | @abc.abstractmethod 20 | def stock_api(self) -> str: 21 | """ 22 | 行情 api 地址 23 | """ 24 | pass 25 | 26 | def __init__(self): 27 | self._session = requests.session() 28 | stock_codes = self.load_stock_codes() 29 | self.stock_list = self.gen_stock_list(stock_codes) 30 | 31 | def gen_stock_list(self, stock_codes): 32 | stock_with_exchange_list = self._gen_stock_prefix(stock_codes) 33 | 34 | if self.max_num > len(stock_with_exchange_list): 35 | request_list = ",".join(stock_with_exchange_list) 36 | return [request_list] 37 | 38 | stock_list = [] 39 | request_num = len(stock_codes) // (self.max_num + 1) + 1 40 | for range_start in range(request_num): 41 | num_start = self.max_num * range_start 42 | num_end = self.max_num * (range_start + 1) 43 | request_list = ",".join( 44 | stock_with_exchange_list[num_start:num_end] 45 | ) 46 | stock_list.append(request_list) 47 | return stock_list 48 | 49 | def _gen_stock_prefix(self, stock_codes): 50 | return [ 51 | easyutils.stock.get_stock_type(code) + code[-6:] 52 | for code in stock_codes 53 | ] 54 | 55 | @staticmethod 56 | def load_stock_codes(): 57 | with open(helpers.stock_code_path()) as f: 58 | return json.load(f)["stock"] 59 | 60 | @property 61 | def all(self): 62 | warnings.warn("use market_snapshot instead", DeprecationWarning) 63 | return self.get_stock_data(self.stock_list) 64 | 65 | @property 66 | def all_market(self): 67 | """return quotation with stock_code prefix key""" 68 | return self.get_stock_data(self.stock_list, prefix=True) 69 | 70 | def stocks(self, stock_codes, prefix=False): 71 | return self.real(stock_codes, prefix) 72 | 73 | def real(self, stock_codes, prefix=False): 74 | """return specific stocks real quotation 75 | :param stock_codes: stock code or list of stock code, 76 | when prefix is True, stock code must start with sh/sz 77 | :param prefix: if prefix i True, stock_codes must contain sh/sz market 78 | flag. If prefix is False, index quotation can't return 79 | :return quotation dict, key is stock_code, value is real quotation. 80 | If prefix with True, key start with sh/sz market flag 81 | 82 | """ 83 | if not isinstance(stock_codes, list): 84 | stock_codes = [stock_codes] 85 | 86 | stock_list = self.gen_stock_list(stock_codes) 87 | return self.get_stock_data(stock_list, prefix=prefix) 88 | 89 | def market_snapshot(self, prefix=False): 90 | """return all market quotation snapshot 91 | :param prefix: if prefix is True, return quotation dict's stock_code 92 | key start with sh/sz market flag 93 | """ 94 | return self.get_stock_data(self.stock_list, prefix=prefix) 95 | 96 | def get_stocks_by_range(self, params): 97 | headers = { 98 | "Accept-Encoding": "gzip, deflate, sdch", 99 | "User-Agent": ( 100 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " 101 | "(KHTML, like Gecko) Chrome/54.0.2840.100 " 102 | "Safari/537.36" 103 | ), 104 | } 105 | 106 | r = self._session.get(self.stock_api + params, headers=headers) 107 | return r.text 108 | 109 | def get_stock_data(self, stock_list, **kwargs): 110 | """获取并格式化股票信息""" 111 | res = self._fetch_stock_data(stock_list) 112 | return self.format_response_data(res, **kwargs) 113 | 114 | def _fetch_stock_data(self, stock_list): 115 | """获取股票信息""" 116 | pool = multiprocessing.pool.ThreadPool(len(stock_list)) 117 | try: 118 | res = pool.map(self.get_stocks_by_range, stock_list) 119 | finally: 120 | pool.close() 121 | return [d for d in res if d is not None] 122 | 123 | def format_response_data(self, rep_data, **kwargs): 124 | pass 125 | -------------------------------------------------------------------------------- /easyquotation/boc.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import re 3 | 4 | import requests 5 | 6 | 7 | class Boc: 8 | """中行美元最新汇率""" 9 | 10 | url = "http://www.boc.cn/sourcedb/whpj/" 11 | 12 | def get_exchange_rate(self, currency="usa"): 13 | rep = requests.get(self.url) 14 | data = re.findall(r"(.*?)", rep.text) 15 | 16 | if currency == "usa": 17 | return {"sell": data[-13], "buy": data[-15]} 18 | return {} 19 | -------------------------------------------------------------------------------- /easyquotation/daykline.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | """ 3 | # pylint: disable=line-too-long 4 | url = "http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk00001,day,,,660,qfq&r=0.7773272375526847" 5 | 6 | url 参数改动 7 | 股票代码 :hk00001 8 | 日k线天数:660 9 | 10 | 更改为需要获取的股票代码和天数例如: 11 | 12 | # pylint: disable=line-too-long 13 | url = "http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk00700,day,,,350,qfq&r=0.7773272375526847" 14 | 15 | """ 16 | import json 17 | import re 18 | 19 | from . import basequotation 20 | 21 | 22 | class DayKline(basequotation.BaseQuotation): 23 | """腾讯免费行情获取""" 24 | 25 | max_num = 1 26 | 27 | @property 28 | def stock_api(self) -> str: 29 | # pylint: disable=line-too-long 30 | return "http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=" 31 | 32 | def _gen_stock_prefix(self, stock_codes, day=1500): 33 | return ["hk{},day,,,{},qfq".format(code, day) for code in stock_codes] 34 | 35 | def format_response_data(self, rep_data, **kwargs): 36 | stock_dict = {} 37 | for raw_quotation in rep_data: 38 | raw_stocks_detail = re.search(r"=(.*)", raw_quotation).group(1) 39 | stock_details = json.loads(raw_stocks_detail) 40 | for stock, value in stock_details["data"].items(): 41 | stock_code = stock[2:] 42 | stock_detail = value["qfqday"] 43 | stock_dict[stock_code] = stock_detail 44 | break 45 | 46 | return stock_dict 47 | 48 | 49 | if __name__ == "__main__": 50 | pass 51 | -------------------------------------------------------------------------------- /easyquotation/helpers.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | 8 | STOCK_CODE_PATH = "stock_codes.conf" 9 | 10 | 11 | def update_stock_codes(): 12 | """获取所有股票 ID 到 all_stock_code 目录下""" 13 | all_stock_codes_url = "http://www.shdjt.com/js/lib/astock.js" 14 | grep_stock_codes = re.compile(r"~(\d+)`") 15 | response = requests.get(all_stock_codes_url) 16 | all_stock_codes = grep_stock_codes.findall(response.text) 17 | with open(stock_code_path(), "w") as f: 18 | f.write(json.dumps(dict(stock=all_stock_codes))) 19 | 20 | 21 | def get_stock_codes(realtime=False): 22 | """获取所有股票 ID 到 all_stock_code 目录下""" 23 | if realtime: 24 | all_stock_codes_url = "http://www.shdjt.com/js/lib/astock.js" 25 | grep_stock_codes = re.compile(r"~(\d+)`") 26 | response = requests.get(all_stock_codes_url) 27 | stock_codes = grep_stock_codes.findall(response.text) 28 | with open(stock_code_path(), "w") as f: 29 | f.write(json.dumps(dict(stock=stock_codes))) 30 | return stock_codes 31 | 32 | with open(stock_code_path()) as f: 33 | return json.load(f)["stock"] 34 | 35 | 36 | def stock_code_path(): 37 | return os.path.join(os.path.dirname(__file__), STOCK_CODE_PATH) 38 | -------------------------------------------------------------------------------- /easyquotation/hkqoute.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | """ 3 | url = "http://sqt.gtimg.cn/utf8/q=r_hk00981" 4 | 5 | url 参数改动 6 | 股票代码 q=r_hk00981 7 | """ 8 | 9 | 10 | import re 11 | 12 | from . import basequotation 13 | 14 | 15 | class HKQuote(basequotation.BaseQuotation): 16 | """腾讯免费行情获取""" 17 | 18 | @property 19 | def stock_api(self) -> str: 20 | return "http://sqt.gtimg.cn/utf8/q=" 21 | 22 | def _gen_stock_prefix(self, stock_codes): 23 | return ["r_hk{}".format(code) for code in stock_codes] 24 | 25 | def format_response_data(self, rep_data, **kwargs): 26 | stocks_detail = "".join(rep_data) 27 | 28 | stock_dict = {} 29 | for raw_quotation in re.findall(r'v_r_hk\d+=".*?"', stocks_detail): 30 | quotation = re.search('"(.*?)"', raw_quotation).group(1).split("~") 31 | stock_dict[quotation[2]] = dict( 32 | lotSize=float(quotation[0]), 33 | name=quotation[1], 34 | price=float(quotation[3]), 35 | lastPrice=float(quotation[4]), 36 | openPrice=float(quotation[5]), 37 | amount=float(quotation[6]), 38 | time=quotation[30], 39 | high=float(quotation[33]), 40 | low=float(quotation[34]), 41 | ) 42 | return stock_dict 43 | -------------------------------------------------------------------------------- /easyquotation/jsl.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | """ 3 | 获取集思路的数据 4 | """ 5 | import json 6 | import time 7 | 8 | import requests 9 | 10 | 11 | class Jsl: 12 | """ 13 | 抓取集思路的分级A数据 14 | """ 15 | 16 | # 分级A的接口 17 | __funda_url = "http://www.jisilu.cn/data/sfnew/funda_list/?___t={ctime:d}" 18 | 19 | # 分级B的接口 20 | __fundb_url = "http://www.jisilu.cn/data/sfnew/fundb_list/?___t={ctime:d}" 21 | 22 | # 母基接口 23 | __fundm_url = "https://www.jisilu.cn/data/sfnew/fundm_list/?___t={ctime:d}" 24 | 25 | # 分级套利的接口 26 | __fundarb_url = ( 27 | "http://www.jisilu.cn/data/sfnew/arbitrage_vip_list/?___t={ctime:d}" 28 | ) 29 | 30 | # 集思录登录接口 31 | __jsl_login_url = "https://www.jisilu.cn/account/ajax/login_process/" 32 | 33 | # 集思录 ETF 接口 34 | __etf_index_url = "https://www.jisilu.cn/jisiludata/etf.php?___t={ctime:d}" 35 | # 黄金 ETF , 货币 ETF 留坑,未完成 36 | __etf_gold_url = ( 37 | "https://www.jisilu.cn/jisiludata/etf.php?qtype=pmetf&___t={ctime:d}" 38 | ) 39 | __etf_money_url = ( 40 | "https://www.jisilu.cn/data/money_fund/list/?___t={ctime:d}" 41 | ) 42 | 43 | # 集思录QDII接口 44 | __qdii_url = "https://www.jisilu.cn/data/qdii/qdii_list/?___t={ctime:d}" 45 | # 可转债 46 | __cb_url = "https://www.jisilu.cn/data/cbnew/cb_list/?___t={ctime:d}" 47 | 48 | # 分级A数据 49 | # 返回的字典格式 50 | # { 150022: 51 | # {'abrate': '5:5', 52 | # 'calc_info': None, 53 | # 'coupon_descr': '+3.0%', 54 | # 'coupon_descr_s': '+3.0%', 55 | # 'fund_descr': '每年第一个工作日定折,无下折,A不参与上折,净值<1元无定折', 56 | # 'funda_amount': 178823, 57 | # 'funda_amount_increase': '0', 58 | # 'funda_amount_increase_rt': '0.00%', 59 | # 'funda_base_est_dis_rt': '2.27%', 60 | # 'funda_base_est_dis_rt_t1': '2.27%', 61 | # 'funda_base_est_dis_rt_t2': '-0.34%', 62 | # 'funda_base_est_dis_rt_tip': '', 63 | # 'funda_base_fund_id': '163109', 64 | # 'funda_coupon': '5.75', 65 | # 'funda_coupon_next': '4.75', 66 | # 'funda_current_price': '0.783', 67 | # 'funda_discount_rt': '24.75%', 68 | # 'funda_id': '150022', 69 | # 'funda_increase_rt': '0.00%', 70 | # 'funda_index_id': '399001', 71 | # 'funda_index_increase_rt': '0.00%', 72 | # 'funda_index_name': '深证成指', 73 | # 'funda_left_year': '永续', 74 | # 'funda_lower_recalc_rt': '1.82%', 75 | # 'funda_name': '深成指A', 76 | # 'funda_nav_dt': '2015-09-14', 77 | # 'funda_profit_rt': '7.74%', 78 | # 'funda_profit_rt_next': '6.424%', 79 | # 'funda_value': '1.0405', 80 | # 'funda_volume': '0.00', 81 | # 'fundb_upper_recalc_rt': '244.35%', 82 | # 'fundb_upper_recalc_rt_info': '深成指A不参与上折', 83 | # 'last_time': '09:18:22', 84 | # 'left_recalc_year': '0.30411', 85 | # 'lower_recalc_profit_rt': '-', 86 | # 'next_recalc_dt': '2016-01-04', 87 | # 'owned': 0, 88 | # 'status_cd': 'N'} 89 | # } 90 | 91 | def __init__(self): 92 | self.__funda = None 93 | self.__fundm = None 94 | self.__fundb = None 95 | self.__fundarb = None 96 | self.__etfindex = None 97 | self.__qdii = None 98 | self.__cb = None 99 | 100 | @staticmethod 101 | def formatfundajson(fundajson): 102 | """格式化集思录返回的json数据,以字典形式保存""" 103 | result = {} 104 | for row in fundajson["rows"]: 105 | funda_id = row["id"] 106 | cell = row["cell"] 107 | result[funda_id] = cell 108 | return result 109 | 110 | @staticmethod 111 | def formatfundbjson(fundbjson): 112 | """格式化集思录返回的json数据,以字典形式保存""" 113 | result = {} 114 | for row in fundbjson["rows"]: 115 | cell = row["cell"] 116 | fundb_id = cell["fundb_id"] 117 | result[fundb_id] = cell 118 | return result 119 | 120 | @staticmethod 121 | def formatetfindexjson(fundbjson): 122 | """格式化集思录返回 指数ETF 的json数据,以字典形式保存""" 123 | result = {} 124 | for row in fundbjson["rows"]: 125 | cell = row["cell"] 126 | fundb_id = cell["fund_id"] 127 | result[fundb_id] = cell 128 | return result 129 | 130 | @staticmethod 131 | def formatjisilujson(data): 132 | result = {} 133 | for row in data["rows"]: 134 | cell = row["cell"] 135 | id_ = row["id"] 136 | result[id_] = cell 137 | return result 138 | 139 | @staticmethod 140 | def percentage2float(per): 141 | """ 142 | 将字符串的百分数转化为浮点数 143 | :param per: 144 | :return: 145 | """ 146 | return float(per.strip("%")) / 100. 147 | 148 | def funda( 149 | self, 150 | fields=None, 151 | min_volume=0, 152 | min_discount=0, 153 | ignore_nodown=False, 154 | forever=False, 155 | ): 156 | """以字典形式返回分级A数据 157 | :param fields:利率范围,形如['+3.0%', '6.0%'] 158 | :param min_volume:最小交易量,单位万元 159 | :param min_discount:最小折价率, 单位% 160 | :param ignore_nodown:是否忽略无下折品种,默认 False 161 | :param forever: 是否选择永续品种,默认 False 162 | """ 163 | if fields is None: 164 | fields = [] 165 | 166 | # 添加当前的ctime 167 | self.__funda_url = self.__funda_url.format(ctime=int(time.time())) 168 | # 请求数据 169 | rep = requests.get(self.__funda_url) 170 | # 获取返回的json字符串 171 | fundajson = json.loads(rep.text) 172 | # 格式化返回的json字符串 173 | data = self.formatfundajson(fundajson) 174 | # 过滤小于指定交易量的数据 175 | if min_volume: 176 | data = { 177 | k: data[k] 178 | for k in data 179 | if float(data[k]["funda_volume"]) > min_volume 180 | } 181 | if len(fields): 182 | data = { 183 | k: data[k] 184 | for k in data 185 | if data[k]["coupon_descr_s"] in "".join(fields) 186 | } 187 | if ignore_nodown: 188 | data = { 189 | k: data[k] 190 | for k in data 191 | if data[k]["fund_descr"].find("无下折") == -1 192 | } 193 | if forever: 194 | data = { 195 | k: data[k] 196 | for k in data 197 | if data[k]["funda_left_year"].find("永续") != -1 198 | } 199 | if min_discount: 200 | data = { 201 | k: data[k] 202 | for k in data 203 | if float(data[k]["funda_discount_rt"][:-1]) > min_discount 204 | } 205 | 206 | self.__funda = data 207 | return self.__funda 208 | 209 | def fundm(self): 210 | """以字典形式返回分级母基数据 211 | """ 212 | # 添加当前的ctime 213 | self.__fundm_url = self.__fundm_url.format(ctime=int(time.time())) 214 | # 请求数据 215 | rep = requests.get(self.__fundm_url) 216 | # 获取返回的json字符串 217 | fundmjson = json.loads(rep.text) 218 | # 格式化返回的json字符串 219 | data = self.formatfundajson(fundmjson) 220 | self.__fundm = data 221 | return self.__fundm 222 | 223 | def fundb(self, fields=None, min_volume=0, min_discount=0, forever=False): 224 | """以字典形式返回分级B数据 225 | :param fields:利率范围,形如['+3.0%', '6.0%'] 226 | :param min_volume:最小交易量,单位万元 227 | :param min_discount:最小折价率, 单位% 228 | :param forever: 是否选择永续品种,默认 False 229 | """ 230 | if fields is None: 231 | fields = [] 232 | # 添加当前的ctime 233 | self.__fundb_url = self.__fundb_url.format(ctime=int(time.time())) 234 | # 请求数据 235 | rep = requests.get(self.__fundb_url) 236 | # 获取返回的json字符串 237 | fundbjson = json.loads(rep.text) 238 | # 格式化返回的json字符串 239 | data = self.formatfundbjson(fundbjson) 240 | # 过滤小于指定交易量的数据 241 | if min_volume: 242 | data = { 243 | k: data[k] 244 | for k in data 245 | if float(data[k]["fundb_volume"]) > min_volume 246 | } 247 | if len(fields): 248 | data = { 249 | k: data[k] 250 | for k in data 251 | if data[k]["coupon_descr_s"] in "".join(fields) 252 | } 253 | if forever: 254 | data = { 255 | k: data[k] 256 | for k in data 257 | if data[k]["fundb_left_year"].find("永续") != -1 258 | } 259 | if min_discount: 260 | data = { 261 | k: data[k] 262 | for k in data 263 | if float(data[k]["fundb_discount_rt"][:-1]) > min_discount 264 | } 265 | self.__fundb = data 266 | return self.__fundb 267 | 268 | def fundarb( 269 | self, 270 | jsl_username, 271 | jsl_password, 272 | avolume=100, 273 | bvolume=100, 274 | ptype="price", 275 | ): 276 | """以字典形式返回分级A数据 277 | :param jsl_username: 集思录用户名 278 | :param jsl_password: 集思路登录密码 279 | :param avolume: A成交额,单位百万 280 | :param bvolume: B成交额,单位百万 281 | :param ptype: 溢价计算方式,price=现价,buy=买一,sell=卖一 282 | """ 283 | session = requests.session() 284 | headers = { 285 | # pylint: disable=line-too-long 286 | "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" 287 | } 288 | session.headers.update(headers) 289 | 290 | logindata = dict( 291 | return_url="http://www.jisilu.cn/", 292 | user_name=jsl_username, 293 | password=jsl_password, 294 | net_auto_login="1", 295 | _post_type="ajax", 296 | ) 297 | 298 | rep = session.post(self.__jsl_login_url, data=logindata) 299 | 300 | if rep.json()["err"] is not None: 301 | return rep.json() 302 | 303 | # 添加当前的ctime 304 | fundarb_url = self.__fundarb_url.format(ctime=int(time.time())) 305 | 306 | pdata = dict( 307 | avolume=avolume, 308 | bvolume=bvolume, 309 | ptype=ptype, 310 | is_search="1", 311 | market=["sh", "sz"], 312 | rp="50", 313 | ) 314 | # 请求数据 315 | rep = session.post(fundarb_url, data=pdata) 316 | 317 | # 获取返回的json字符串 318 | fundajson = json.loads(rep.text) 319 | # 格式化返回的json字符串 320 | data = self.formatfundajson(fundajson) 321 | 322 | self.__fundarb = data 323 | return self.__fundarb 324 | 325 | def etfindex( 326 | self, index_id="", min_volume=0, max_discount=None, min_discount=None 327 | ): 328 | """ 329 | 以字典形式返回 指数ETF 数据 330 | :param index_id: 获取指定的指数 331 | :param min_volume: 最小成交量 332 | :param min_discount: 最低溢价率, 适用于溢价套利, 格式 "-1.2%", "-1.2", -0.012 三种均可 333 | :param max_discount: 最高溢价率, 适用于折价套利, 格式 "-1.2%", "-1.2", -0.012 三种均可 334 | :return: {"fund_id":{}} 335 | """ 336 | # 添加当前的ctime 337 | self.__etf_index_url = self.__etf_index_url.format( 338 | ctime=int(time.time()) 339 | ) 340 | # 请求数据 341 | rep = requests.get(self.__etf_index_url) 342 | # 获取返回的json字符串, 转化为字典 343 | etf_json = rep.json() 344 | 345 | # 格式化返回的json字符串 346 | data = self.formatetfindexjson(etf_json) 347 | 348 | # 过滤 349 | if index_id: 350 | # 指定跟踪的指数代码 351 | data = { 352 | fund_id: cell 353 | for fund_id, cell in data.items() 354 | if cell["index_id"] == index_id 355 | } 356 | if min_volume: 357 | # 过滤小于指定交易量的数据 358 | data = { 359 | fund_id: cell 360 | for fund_id, cell in data.items() 361 | if float(cell["volume"]) >= min_volume 362 | } 363 | if min_discount is not None: 364 | # 指定最小溢价率 365 | if isinstance(min_discount, str): 366 | if min_discount.endswith("%"): 367 | # 如果是字符串形式,先转为浮点形式 368 | min_discount = self.percentage2float(min_discount) 369 | else: 370 | min_discount = float(min_discount) / 100. 371 | data = { 372 | fund_id: cell 373 | for fund_id, cell in data.items() 374 | if self.percentage2float(cell["discount_rt"]) >= min_discount 375 | } 376 | if max_discount is not None: 377 | # 指定最大溢价率 378 | if isinstance(max_discount, str): 379 | if max_discount.endswith("%"): 380 | # 如果是字符串形式,先转为浮点形式 381 | max_discount = self.percentage2float(max_discount) 382 | else: 383 | max_discount = float(max_discount) / 100. 384 | data = { 385 | fund_id: cell 386 | for fund_id, cell in data.items() 387 | if self.percentage2float(cell["discount_rt"]) <= max_discount 388 | } 389 | 390 | self.__etfindex = data 391 | return self.__etfindex 392 | 393 | def qdii(self, min_volume=0): 394 | """以字典形式返回QDII数据 395 | :param min_volume:最小交易量,单位万元 396 | """ 397 | # 添加当前的ctime 398 | self.__qdii_url = self.__qdii_url.format(ctime=int(time.time())) 399 | # 请求数据 400 | rep = requests.get(self.__qdii_url) 401 | # 获取返回的json字符串 402 | fundjson = json.loads(rep.text) 403 | # 格式化返回的json字符串 404 | data = self.formatjisilujson(fundjson) 405 | data = {x: y for x, y in data.items() if y["notes"] != "估值有问题"} 406 | # 过滤小于指定交易量的数据 407 | if min_volume: 408 | data = { 409 | k: data[k] 410 | for k in data 411 | if float(data[k]["volume"]) > min_volume 412 | } 413 | 414 | self.__qdii = data 415 | return self.__qdii 416 | 417 | # pylint: disable=invalid-name 418 | def cb(self, min_volume=0): 419 | """以字典形式返回QDII数据 420 | :param min_volume:最小交易量,单位万元 421 | """ 422 | # 添加当前的ctime 423 | self.__cb_url = self.__cb_url.format(ctime=int(time.time())) 424 | # 请求数据 425 | rep = requests.get(self.__cb_url) 426 | # 获取返回的json字符串 427 | fundjson = json.loads(rep.text) 428 | # 格式化返回的json字符串 429 | data = self.formatjisilujson(fundjson) 430 | # 过滤小于指定交易量的数据 431 | if min_volume: 432 | data = { 433 | k: data[k] 434 | for k in data 435 | if float(data[k]["volume"]) > min_volume 436 | } 437 | 438 | self.__cb = data 439 | return self.__cb 440 | 441 | 442 | if __name__ == "__main__": 443 | Jsl().etfindex( 444 | index_id="000016", 445 | min_volume=0, 446 | max_discount="-0.4", 447 | min_discount="-1.3%", 448 | ) 449 | -------------------------------------------------------------------------------- /easyquotation/sina.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import random 3 | import re 4 | 5 | from . import basequotation 6 | 7 | 8 | class Sina(basequotation.BaseQuotation): 9 | """新浪免费行情获取""" 10 | 11 | max_num = 800 12 | grep_detail = re.compile( 13 | r"(\d+)=[^\s]([^,]+?)%s%s" % (r",([\.\d]+)" * 29, r",([-\.\d:]+)" * 2) 14 | ) 15 | grep_detail_with_prefix = re.compile( 16 | r"(\w{2}\d+)=[^\s]([^,]+?)%s%s" 17 | % (r",([\.\d]+)" * 29, r",([-\.\d:]+)" * 2) 18 | ) 19 | 20 | @property 21 | def stock_api(self) -> str: 22 | return f"http://hq.sinajs.cn/rn={self._random()}&list=" 23 | 24 | @staticmethod 25 | def _random(length=13) -> str: 26 | start = 10 ** (length - 1) 27 | end = (10 ** length) - 1 28 | return str(random.randint(start, end)) 29 | 30 | def format_response_data(self, rep_data, prefix=False): 31 | stocks_detail = "".join(rep_data) 32 | grep_str = self.grep_detail_with_prefix if prefix else self.grep_detail 33 | result = grep_str.finditer(stocks_detail) 34 | stock_dict = dict() 35 | for stock_match_object in result: 36 | stock = stock_match_object.groups() 37 | stock_dict[stock[0]] = dict( 38 | name=stock[1], 39 | open=float(stock[2]), 40 | close=float(stock[3]), 41 | now=float(stock[4]), 42 | high=float(stock[5]), 43 | low=float(stock[6]), 44 | buy=float(stock[7]), 45 | sell=float(stock[8]), 46 | turnover=int(stock[9]), 47 | volume=float(stock[10]), 48 | bid1_volume=int(stock[11]), 49 | bid1=float(stock[12]), 50 | bid2_volume=int(stock[13]), 51 | bid2=float(stock[14]), 52 | bid3_volume=int(stock[15]), 53 | bid3=float(stock[16]), 54 | bid4_volume=int(stock[17]), 55 | bid4=float(stock[18]), 56 | bid5_volume=int(stock[19]), 57 | bid5=float(stock[20]), 58 | ask1_volume=int(stock[21]), 59 | ask1=float(stock[22]), 60 | ask2_volume=int(stock[23]), 61 | ask2=float(stock[24]), 62 | ask3_volume=int(stock[25]), 63 | ask3=float(stock[26]), 64 | ask4_volume=int(stock[27]), 65 | ask4=float(stock[28]), 66 | ask5_volume=int(stock[29]), 67 | ask5=float(stock[30]), 68 | date=stock[31], 69 | time=stock[32], 70 | ) 71 | return stock_dict 72 | -------------------------------------------------------------------------------- /easyquotation/stock_codes.conf: -------------------------------------------------------------------------------- 1 | {"stock": ["000001", "000002", "000004", "000005", "000006", "000007", "000008", "000009", "000010", "000011", "000012", "000014", "000016", "000017", "000018", "000019", "000020", "000021", "000022", "000023", "000025", "000026", "000027", "000028", "000029", "000030", "000031", "000032", "000034", "000035", "000036", "000037", "000038", "000039", "000040", "000042", "000043", "000045", "000046", "000048", "000049", "000050", "000055", "000056", "000058", "000059", "000060", "000061", "000062", "000063", "000065", "000066", "000068", "000069", "000070", "000078", "000088", "000089", "000090", "000096", "000099", "000100", "000150", "000151", "000153", "000155", "000156", "000157", "000158", "000159", "000166", "000301", "000333", "000338", "000400", "000401", "000402", "000403", "000404", "000407", "000408", "000409", "000410", "000410", "000411", "000413", "000415", "000416", "000417", "000418", "000419", "000420", "000421", "000422", "000423", "000425", "000426", "000428", "000429", "000430", "000488", "000498", "000501", "000502", "000503", "000504", "000505", "000506", "000507", "000509", "000510", "000513", "000514", "000516", "000517", "000518", "000519", "000520", "000521", "000523", "000524", "000525", "000526", "000528", "000529", "000530", "000531", "000532", "000533", "000534", "000536", "000537", "000538", "000539", "000540", "000541", "000543", "000544", "000545", "000546", "000547", "000548", "000550", "000551", "000552", "000553", "000554", "000555", "000557", "000558", "000559", "000560", "000561", "000563", "000564", "000565", "000566", "000567", "000568", "000570", "000571", "000572", "000573", "000576", "000581", "000582", "000584", "000585", "000586", "000587", "000589", "000590", "000591", "000592", "000593", "000595", "000596", "000597", "000598", "000599", "000600", "000601", "000603", "000605", "000606", "000607", "000608", "000609", "000609", "000610", "000611", "000612", "000613", "000615", "000616", "000617", "000619", "000620", "000622", "000623", "000625", "000626", "000627", "000628", "000630", "000631", "000632", "000633", "000635", "000636", "000637", "000638", "000639", "000650", "000651", "000652", "000655", "000656", "000657", "000659", "000661", "000662", "000663", "000665", "000666", "000667", "000668", "000669", "000670", "000671", "000672", "000673", "000676", "000677", "000678", "000679", "000680", "000681", "000682", "000683", "000685", "000686", "000687", "000688", "000690", "000691", "000692", "000693", "000695", "000697", "000698", "000700", "000701", "000702", "000703", "000705", "000707", "000708", "000709", "000710", "000711", "000712", "000713", "000715", "000716", "000717", "000718", "000719", "000720", "000721", "000722", "000723", "000725", "000726", "000727", "000728", "000729", "000731", "000732", "000733", "000735", "000736", "000737", "000737", "000738", "000739", "000750", "000751", "000752", "000753", "000755", "000756", "000757", "000758", "000759", "000760", "000761", "000762", "000766", "000767", "000768", "000776", "000777", "000778", "000779", "000780", "000782", "000783", "000785", "000786", "000788", "000789", "000790", "000791", "000792", "000793", "000795", "000796", "000797", "000798", "000799", "000800", "000801", "000802", "000803", "000806", "000807", "000809", "000810", "000811", "000812", "000813", "000815", "000816", "000818", "000819", "000820", "000821", "000822", "000823", "000825", "000826", "000828", "000829", "000830", "000831", "000833", "000835", "000836", "000837", "000838", "000839", "000848", "000850", "000851", "000852", "000856", "000858", "000859", "000860", "000861", "000862", "000863", "000868", "000869", "000875", "000876", "000877", "000878", "000880", "000881", "000882", "000883", "000885", "000886", "000887", "000888", "000889", "000890", "000892", "000893", "000895", "000897", "000898", "000899", "000900", "000901", "000902", "000903", "000905", "000906", "000908", "000909", "000910", "000911", "000912", "000913", "000915", "000916", "000917", "000918", "000919", "000920", "000921", "000922", "000923", "000925", "000926", "000927", "000928", "000929", "000930", "000931", "000932", "000932", "000933", "000935", "000936", "000937", "000938", "000939", "000948", "000949", "000951", "000952", "000953", "000955", "000957", "000958", "000959", "000960", "000961", "000962", "000963", "000965", "000966", "000967", "000968", "000969", "000970", "000971", "000972", "000973", "000975", "000976", "000977", "000978", "000979", "000980", "000981", "000982", "000983", "000985", "000987", "000988", "000989", "000990", "000993", "000995", "000996", "000997", "000998", "000999", "001696", "001896", "001965", "001979", "002001", "002002", "002003", "002004", "002005", "002006", "002007", "002008", "002009", "002010", "002011", "002012", "002013", "002014", "002015", "002016", "002017", "002018", "002019", "002020", "002021", "002022", "002023", "002024", "002024", "002025", "002026", "002027", "002028", "002029", "002030", "002031", "002032", "002033", "002034", "002035", "002036", "002037", "002038", "002039", "002040", "002041", "002042", "002043", "002044", "002045", "002046", "002047", "002048", "002049", "002050", "002051", "002052", "002053", "002054", "002055", "002056", "002057", "002058", "002059", "002060", "002061", "002062", "002063", "002064", "002065", "002066", "002067", "002068", "002069", "002070", "002071", "002072", "002073", "002074", "002075", "002076", "002077", "002078", "002079", "002080", "002081", "002082", "002083", "002084", "002085", "002086", "002087", "002088", "002089", "002090", "002091", "002092", "002093", "002094", "002095", "002096", "002097", "002098", "002099", "002100", "002101", "002102", "002103", "002104", "002105", "002106", "002107", "002108", "002109", "002110", "002111", "002112", "002113", "002114", "002115", "002116", "002117", "002118", "002119", "002120", "002121", "002122", "002123", "002124", "002125", "002126", "002127", "002128", "002129", "002130", "002131", "002132", "002133", "002134", "002135", "002136", "002137", "002138", "002139", "002140", "002141", "002142", "002143", "002144", "002145", "002146", "002147", "002148", "002149", "002150", "002151", "002152", "002153", "002154", "002155", "002156", "002157", "002158", "002159", "002160", "002161", "002162", "002163", "002164", "002165", "002166", "002167", "002168", "002169", "002170", "002171", "002172", "002173", "002174", "002175", "002176", "002177", "002178", "002179", "002180", "002181", "002182", "002183", "002184", "002185", "002186", "002187", "002188", "002188", "002189", "002190", "002191", "002192", "002193", "002194", "002195", "002196", "002197", "002198", "002199", "002200", "002201", "002202", "002203", "002204", "002205", "002206", "002207", "002208", "002209", "002210", "002211", "002212", "002213", "002214", "002215", "002216", "002217", "002218", "002219", "002220", "002221", "002222", "002223", "002224", "002225", "002226", "002227", "002228", "002229", "002230", "002231", "002232", "002233", "002234", "002235", "002236", "002237", "002238", "002239", "002240", "002241", "002242", "002243", "002244", "002245", "002246", "002247", "002248", "002249", "002250", "002251", "002252", "002253", "002254", "002255", "002256", "002258", "002259", "002260", "002261", "002262", "002263", "002264", "002265", "002266", "002267", "002268", "002269", "002270", "002271", "002272", "002273", "002274", "002275", "002276", "002277", "002278", "002279", "002280", "002281", "002282", "002283", "002284", "002285", "002286", "002287", "002288", "002289", "002290", "002291", "002292", "002293", "002294", "002295", "002296", "002297", "002298", "002299", "002300", "002301", "002302", "002303", "002304", "002305", "002306", "002307", "002308", "002309", "002310", "002311", "002312", "002313", "002314", "002315", "002316", "002317", "002318", "002319", "002320", "002321", "002322", "002323", "002324", "002325", "002326", "002327", "002328", "002329", "002330", "002331", "002332", "002333", "002334", "002335", "002336", "002337", "002338", "002339", "002340", "002341", "002342", "002343", "002344", "002345", "002346", "002347", "002348", "002349", "002350", "002351", "002352", "002353", "002354", "002355", "002356", "002357", "002358", "002359", "002360", "002361", "002362", "002363", "002364", "002365", "002366", "002367", "002368", "002369", "002370", "002371", "002372", "002373", "002374", "002375", "002376", "002377", "002378", "002379", "002380", "002381", "002382", "002383", "002384", "002385", "002386", "002387", "002388", "002389", "002390", "002391", "002392", "002393", "002394", "002395", "002396", "002397", "002398", "002399", "002400", "002401", "002402", "002403", "002404", "002405", "002406", "002407", "002408", "002409", "002410", "002411", "002412", "002413", "002414", "002415", "002416", "002417", "002417", "002418", "002419", "002420", "002421", "002422", "002423", "002424", "002425", "002426", "002427", "002427", "002428", "002429", "002430", "002431", "002432", "002433", "002434", "002435", "002436", "002437", "002438", "002439", "002440", "002441", "002442", "002443", "002444", "002445", "002446", "002447", "002448", "002449", "002450", "002451", "002452", "002453", "002454", "002455", "002456", "002457", "002458", "002459", "002460", "002461", "002462", "002463", "002464", "002465", "002466", "002467", "002468", "002469", "002470", "002471", "002472", "002473", "002474", "002475", "002476", "002477", "002478", "002479", "002480", "002481", "002482", "002483", "002484", "002485", "002486", "002487", "002488", "002489", "002490", "002491", "002492", "002493", "002494", "002495", "002496", "002497", "002498", "002499", "002500", "002501", "002502", "002503", "002504", "002505", "002506", "002507", "002508", "002509", "002510", "002511", "002512", "002513", "002514", "002515", "002516", "002517", "002518", "002519", "002520", "002521", "002522", "002523", "002524", "002526", "002527", "002528", "002529", "002530", "002531", "002532", "002533", "002534", "002535", "002536", "002537", "002538", "002539", "002540", "002541", "002542", "002543", "002544", "002545", "002546", "002547", "002548", "002549", "002550", "002551", "002552", "002553", "002554", "002555", "002556", "002557", "002558", "002559", "002560", "002561", "002562", "002563", "002564", "002565", "002566", "002567", "002568", "002569", "002570", "002571", "002572", "002573", "002574", "002575", "002576", "002577", "002578", "002579", "002580", "002581", "002582", "002583", "002584", "002585", "002586", "002587", "002588", "002589", "002590", "002591", "002592", "002593", "002594", "002595", "002596", "002597", "002598", "002599", "002600", "002600", "002601", "002602", "002603", "002604", "002605", "002606", "002607", "002608", "002609", "002610", "002611", "002612", "002613", "002614", "002615", "002616", "002617", "002618", "002619", "002620", "002621", "002622", "002623", "002624", "002625", "002626", "002627", "002628", "002629", "002630", "002631", "002632", "002633", "002634", "002635", "002636", "002637", "002638", "002639", "002640", "002641", "002642", "002643", "002644", "002645", "002646", "002647", "002648", "002649", "002650", "002651", "002652", "002653", "002654", "002655", "002656", "002657", "002658", "002659", "002660", "002661", "002662", "002663", "002664", "002665", "002666", "002667", "002668", "002669", "002670", "002671", "002672", "002673", "002674", "002675", "002676", "002677", "002678", "002679", "002680", "002681", "002682", "002683", "002684", "002685", "002686", "002687", "002688", "002689", "002690", "002691", "002692", "002693", "002694", "002695", "002696", "002697", "002698", "002699", "002700", "002701", "002702", "002703", "002705", "002706", "002707", "002708", "002709", "002711", "002712", "002713", "002714", "002715", "002716", "002717", "002717", "002718", "002719", "002721", "002722", "002723", "002724", "002725", "002726", "002727", "002728", "002729", "002730", "002731", "002732", "002733", "002734", "002735", "002736", "002737", "002738", "002739", "002740", "002741", "002742", "002743", "002745", "002746", "002747", "002748", "002749", "002750", "002751", "002752", "002753", "002755", "002756", "002757", "002758", "002759", "002760", "002761", "002762", "002763", "002765", "002766", "002767", "002768", "002769", "002770", "002771", "002772", "002773", "002774", "002775", "002776", "002777", "002778", "002779", "002780", "002781", "002782", "002783", "002785", "002786", "002787", "002788", "002789", "002790", "002791", "002792", "002793", "002795", "002796", "002797", "002798", "002799", "002800", "002801", "002802", "002803", "002805", "002806", "002807", "002808", "002809", "002810", "002811", "002812", "002813", "002815", "002816", "002817", "002818", "002819", "002820", "002821", "002822", "002823", "002824", "002825", "002826", "002827", "002828", "002829", "002830", "002831", "002832", "002833", "002835", "002836", "002837", "002838", "002839", "002840", "002841", "002842", "002843", "002845", "002846", "002847", "002848", "002849", "002850", "002851", "002852", "002853", "002855", "002856", "002857", "002858", "002859", "002860", "002861", "002862", "002863", "002864", "002865", "002866", "002867", "002868", "002869", "002870", "002871", "002872", "002873", "002875", "002876", "002877", "002878", "002879", "002880", "002881", "002882", "002883", "002884", "002885", "002886", "002887", "002888", "002889", "002890", "002891", "002892", "002893", "002895", "002896", "002897", "002898", "002899", "002900", "002901", "002902", "002903", "002905", "002906", "002907", "002908", "002909", "002910", "002911", "002912", "002913", "002915", "002916", "002917", "002918", "002919", "002920", "002921", "002922", "002923", "002925", "002926", "002926", "002927", "002927", "002928", "002928", "002929", "002929", "150008", "150009", "150012", "150013", "150016", "150017", "150018", "150019", "150022", "150023", "150028", "150029", "150030", "150031", "150032", "150033", "150036", "150037", "150047", "150048", "150049", "150050", "150051", "150052", "150053", "150054", "150055", "150056", "150057", "150058", "150059", "150060", "150064", "150065", "150066", "150067", "150073", "150075", "150076", "150077", "150083", "150084", "150090", "150091", "150092", "150093", "150094", "150095", "150100", "150101", "150104", "150105", "150106", "150107", "150112", "150113", "150117", "150118", "150121", "150122", "150123", "150124", "150130", "150131", "150135", "150136", "150138", "150139", "150143", "150144", "150145", "150146", "150146", "150148", "150149", "150150", "150151", "150152", "150153", "150157", "150158", "150164", "150165", "150167", "150168", "150169", "150170", "150171", "150172", "150173", "150174", "150175", "150176", "150177", "150178", "150179", "150180", "150181", "150182", "150184", "150185", "150186", "150187", "150187", "150188", "150189", "150190", "150191", "150192", "150193", "150194", "150195", "150196", "150197", "150198", "150199", "150200", "150201", "150201", "150203", "150204", "150205", "150206", "150207", "150208", "150209", "150210", "150211", "150212", "150213", "150214", "150214", "150215", "150216", "150217", "150218", "150219", "150220", "150221", "150222", "150222", "150223", "150224", "150225", "150226", "150227", "150228", "150229", "150230", "150231", "150232", "150233", "150234", "150235", "150236", "150237", "150238", "150241", "150242", "150243", "150244", "150245", "150246", "150247", "150248", "150249", "150250", "150251", "150252", "150255", "150256", "150257", "150258", "150259", "150260", "150261", "150262", "150263", "150264", "150264", "150265", "150266", "150267", "150268", "150269", "150270", "150271", "150272", "150273", "150274", "150275", "150276", "150277", "150278", "150278", "150279", "150280", "150281", "150282", "150283", "150284", "150287", "150288", "150289", "150290", "150291", "150292", "150293", "150294", "150295", "150296", "150297", "150298", "150299", "150300", "150301", "150302", "150303", "150304", "150305", "150306", "150307", "150308", "150309", "150310", "150311", "150312", "150315", "150316", "150317", "150318", "150321", "150322", "150323", "150324", "150324", "150325", "150326", "150327", "150328", "150329", "150330", "150331", "150332", "150332", "150335", "150336", "150343", "150344", "159001", "159003", "159005", "159901", "159902", "159903", "159905", "159906", "159907", "159908", "159909", "159910", "159911", "159912", "159913", "159915", "159916", "159918", "159919", "159920", "159922", "159923", "159924", "159925", "159926", "159927", "159928", "159929", "159930", "159931", "159932", "159933", "159934", "159935", "159936", "159937", "159938", "159939", "159940", "159941", "159942", "159943", "159944", "159945", "159946", "159948", "159949", "159950", "159951", "159952", "159953", "159955", "159957", "160105", "160106", "160119", "160125", "160128", "160130", "160131", "160133", "160138", "160140", "160211", "160212", "160215", "160216", "160220", "160223", "160225", "160311", "160314", "160322", "160323", "160324", "160415", "160416", "160421", "160422", "160505", "160512", "160513", "160515", "160518", "160519", "160520", "160522", "160607", "160610", "160611", "160613", "160615", "160616", "160617", "160618", "160621", "160622", "160635", "160642", "160643", "160644", "160706", "160716", "160717", "160719", "160720", "160722", "160723", "160805", "160806", "160807", "160812", "160813", "160910", "160915", "160916", "160918", "160919", "160921", "160922", "160923", "160924", "161005", "161010", "161014", "161015", "161017", "161019", "161033", "161035", "161036", "161037", "161038", "161115", "161116", "161117", "161119", "161124", "161125", "161126", "161127", "161128", "161129", "161130", "161210", "161213", "161216", "161217", "161219", "161222", "161224", "161225", "161226", "161227", "161229", "161230", "161232", "161233", "161505", "161607", "161610", "161614", "161626", "161631", "161706", "161713", "161714", "161715", "161716", "161722", "161727", "161810", "161813", "161815", "161820", "161823", "161831", "161834", "161835", "161836", "161903", "161907", "161908", "161911", "162006", "162105", "162108", "162207", "162215", "162307", "162411", "162414", "162415", "162510", "162605", "162607", "162703", "162711", "162712", "162715", "162717", "162718", "162719", "163001", "163003", "163005", "163110", "163111", "163119", "163208", "163210", "163302", "163402", "163407", "163409", "163412", "163415", "163503", "163801", "163819", "163821", "163824", "163827", "163907", "164105", "164206", "164208", "164210", "164302", "164403", "164509", "164606", "164701", "164702", "164703", "164705", "164808", "164810", "164812", "164814", "164823", "164902", "164906", "165309", "165311", "165313", "165315", "165317", "165508", "165509", "165510", "165512", "165513", "165516", "165517", "165525", "165528", "165705", "165806", "165807", "166001", "166006", "166007", "166008", "166009", "166011", "166012", "166016", "166023", "166024", "166105", "166401", "166402", "166902", "166904", "167001", "167002", "167003", "167301", "167501", "168002", "168101", "168102", "168103", "168104", "168105", "168106", "168108", "168301", "168401", "169101", "169102", "169103", "169104", "169105", "169201", "184801", "200011", "200012", "200016", "200017", "200018", "200019", "200020", "200022", "200025", "200026", "200028", "200029", "200030", "200037", "200045", "200053", "200054", "200055", "200056", "200058", "200152", "200160", "200168", "200413", "200418", "200429", "200488", "200505", "200512", "200521", "200530", "200539", "200541", "200550", "200553", "200570", "200581", "200596", "200613", "200625", "200706", "200725", "200726", "200761", "200771", "200869", "200986", "200992", "300001", "300002", "300003", "300004", "300005", "300006", "300007", "300008", "300009", "300010", "300011", "300012", "300013", "300014", "300015", "300016", "300017", "300018", "300019", "300020", "300021", "300022", "300023", "300024", "300025", "300026", "300027", "300028", "300029", "300030", "300031", "300032", "300033", "300034", "300035", "300036", "300037", "300038", "300039", "300040", "300041", "300042", "300043", "300044", "300045", "300046", "300047", "300048", "300049", "300050", "300051", "300052", "300053", "300054", "300055", "300056", "300057", "300058", "300059", "300061", "300062", "300063", "300064", "300065", "300066", "300067", "300068", "300069", "300070", "300071", "300072", "300073", "300074", "300075", "300076", "300077", "300078", "300079", "300080", "300081", "300082", "300083", "300084", "300085", "300086", "300087", "300088", "300089", "300090", "300091", "300092", "300093", "300094", "300095", "300096", "300097", "300098", "300099", "300100", "300101", "300102", "300103", "300104", "300105", "300106", "300107", "300108", "300109", "300110", "300111", "300112", "300113", "300114", "300115", "300116", "300117", "300118", "300119", "300120", "300121", "300122", "300123", "300124", "300125", "300126", "300127", "300128", "300129", "300130", "300131", "300132", "300133", "300134", "300135", "300136", "300137", "300138", "300139", "300140", "300141", "300142", "300143", "300144", "300145", "300146", "300147", "300148", "300149", "300150", "300151", "300152", "300153", "300154", "300155", "300156", "300157", "300158", "300159", "300160", "300161", "300162", "300163", "300164", "300165", "300166", "300167", "300168", "300169", "300170", "300171", "300172", "300173", "300174", "300175", "300176", "300177", "300178", "300179", "300180", "300181", "300182", "300183", "300184", "300185", "300187", "300188", "300189", "300190", "300191", "300192", "300193", "300194", "300195", "300196", "300197", "300198", "300199", "300200", "300201", "300202", "300203", "300204", "300205", "300206", "300207", "300208", "300209", "300210", "300211", "300212", "300213", "300214", "300215", "300216", "300217", "300218", "300219", "300220", "300221", "300222", "300223", "300224", "300225", "300226", "300227", "300228", "300229", "300230", "300231", "300232", "300233", "300234", "300235", "300236", "300237", "300238", "300239", "300240", "300241", "300242", "300243", "300244", "300245", "300246", "300247", "300248", "300249", "300250", "300251", "300252", "300253", "300254", "300255", "300256", "300257", "300258", "300259", "300260", "300261", "300262", "300263", "300264", "300265", "300266", "300267", "300268", "300269", "300270", "300271", "300272", "300273", "300274", "300275", "300276", "300277", "300278", "300279", "300280", "300281", "300282", "300283", "300284", "300285", "300286", "300287", "300288", "300289", "300290", "300291", "300292", "300293", "300294", "300295", "300296", "300297", "300298", "300299", "300300", "300301", "300302", "300303", "300304", "300305", "300306", "300307", "300308", "300309", "300310", "300311", "300312", "300313", "300314", "300315", "300316", "300317", "300318", "300319", "300320", "300321", "300322", "300323", "300324", "300325", "300326", "300327", "300328", "300329", "300330", "300331", "300332", "300333", "300334", "300335", "300336", "300337", "300338", "300339", "300340", "300341", "300342", "300343", "300344", "300345", "300346", "300347", "300348", "300349", "300350", "300351", "300352", "300353", "300354", "300355", "300356", "300357", "300358", "300359", "300360", "300362", "300363", "300364", "300365", "300366", "300367", "300368", "300369", "300370", "300371", "300373", "300374", "300375", "300376", "300377", "300378", "300379", "300380", "300381", "300382", "300383", "300384", "300385", "300386", "300387", "300388", "300389", "300390", "300391", "300392", "300393", "300394", "300395", "300396", "300397", "300398", "300399", "300400", "300401", "300402", "300403", "300404", "300405", "300406", "300407", "300408", "300409", "300410", "300411", "300412", "300413", "300414", "300415", "300416", "300417", "300418", "300419", "300420", "300421", "300422", "300423", "300424", "300425", "300426", "300427", "300427", "300428", "300429", "300430", "300431", "300432", "300433", "300434", "300435", "300436", "300437", "300438", "300439", "300440", "300441", "300442", "300443", "300444", "300445", "300446", "300447", "300448", "300449", "300450", "300451", "300452", "300453", "300455", "300456", "300457", "300458", "300459", "300460", "300461", "300462", "300463", "300464", "300465", "300466", "300467", "300468", "300469", "300470", "300471", "300472", "300473", "300474", "300475", "300476", "300477", "300478", "300479", "300480", "300481", "300482", "300483", "300484", "300485", "300486", "300487", "300488", "300489", "300490", "300491", "300492", "300493", "300494", "300495", "300496", "300497", "300498", "300499", "300500", "300501", "300502", "300503", "300505", "300506", "300507", "300508", "300509", "300510", "300511", "300512", "300513", "300514", "300515", "300516", "300517", "300518", "300519", "300520", "300521", "300522", "300523", "300525", "300526", "300527", "300528", "300529", "300530", "300531", "300532", "300533", "300534", "300535", "300536", "300537", "300538", "300539", "300540", "300541", "300542", "300543", "300545", "300546", "300547", "300548", "300549", "300550", "300551", "300552", "300553", "300554", "300555", "300556", "300557", "300558", "300559", "300560", "300561", "300562", "300563", "300565", "300566", "300567", "300568", "300569", "300570", "300571", "300572", "300573", "300575", "300576", "300577", "300578", "300579", "300580", "300581", "300582", "300583", "300584", "300585", "300586", "300587", "300588", "300589", "300590", "300591", "300592", "300593", "300595", "300596", "300597", "300598", "300599", "300600", "300601", "300602", "300603", "300604", "300605", "300606", "300607", "300608", "300609", "300610", "300611", "300612", "300613", "300615", "300616", "300617", "300618", "300619", "300620", "300621", "300622", "300623", "300624", "300625", "300626", "300627", "300628", "300629", "300630", "300631", "300632", "300633", "300635", "300636", "300637", "300638", "300639", "300640", "300641", "300642", "300643", "300644", "300644", "300645", "300647", "300648", "300649", "300650", "300651", "300652", "300653", "300654", "300655", "300656", "300657", "300658", "300659", "300660", "300661", "300662", "300663", "300664", "300665", "300666", "300667", "300668", "300669", "300670", "300671", "300672", "300673", "300675", "300676", "300677", "300678", "300679", "300680", "300681", "300682", "300683", "300684", "300685", "300686", "300687", "300688", "300689", "300690", "300691", "300692", "300693", "300695", "300696", "300697", "300698", "300699", "300700", "300701", "300702", "300703", "300705", "300706", "300707", "300708", "300709", "300710", "300711", "300712", "300713", "300715", "300716", "300717", "300718", "300719", "300720", "300721", "300722", "300723", "300725", "300726", "300727", "300729", "300730", "300731", "300732", "300733", "300735", "300736", "300737", "300738", "300739", "300740", "300740", "300741", "300741", "399001", "399002", "399003", "399004", "399005", "399006", "399007", "399008", "399009", "399010", "399011", "399012", "399013", "399015", "399016", "399017", "399018", "399100", "399101", "399102", "399103", "399106", "399107", "399108", "399231", "399232", "399233", "399234", "399235", "399236", "399237", "399238", "399239", "399240", "399241", "399242", "399243", "399244", "399248", "399249", "399297", "399298", "399299", "399300", "399301", "399302", "399303", "399306", "399307", "399310", "399311", "399312", "399313", "399314", "399315", "399316", "399317", "399318", "399319", "399320", "399321", "399322", "399324", "399326", "399328", "399330", "399333", "399335", "399337", "399339", "399341", "399344", "399346", "399348", "399350", "399351", "399352", "399353", "399354", "399355", "399356", "399357", "399358", "399359", "399360", "399361", "399362", "399363", "399364", "399365", "399366", "399367", "399368", "399369", "399370", "399371", "399372", "399373", "399374", "399375", "399376", "399377", "399378", "399379", "399380", "399381", "399382", "399383", "399384", "399385", "399386", "399387", "399388", "399389", "399390", "399391", "399392", "399393", "399394", "399395", "399396", "399397", "399398", "399399", "399400", "399401", "399402", "399403", "399404", "399405", "399406", "399407", "399408", "399409", "399410", "399411", "399412", "399413", "399415", "399416", "399417", "399418", "399419", "399420", "399422", "399423", "399427", "399428", "399429", "399431", "399432", "399433", "399434", "399435", "399436", "399437", "399438", "399439", "399440", "399441", "399481", "399550", "399551", "399552", "399553", "399554", "399555", "399556", "399557", "399602", "399604", "399606", "399608", "399610", "399611", "399612", "399613", "399614", "399615", "399616", "399617", "399618", "399619", "399620", "399621", "399622", "399623", "399624", "399625", "399626", "399627", "399628", "399629", "399630", "399631", "399632", "399633", "399634", "399635", "399636", "399637", "399638", "399639", "399640", "399641", "399642", "399643", "399644", "399645", "399646", "399647", "399648", "399649", "399650", "399651", "399652", "399653", "399654", "399655", "399656", "399657", "399658", "399659", "399660", "399661", "399662", "399663", "399664", "399665", "399666", "399667", "399668", "399669", "399670", "399671", "399672", "399673", "399674", "399675", "399676", "399677", "399678", "399679", "399680", "399681", "399682", "399683", "399684", "399685", "399686", "399687", "399688", "399689", "399690", "399691", "399692", "399693", "399694", "399695", "399696", "399697", "399698", "399699", "399701", "399702", "399703", "399704", "399705", "399706", "399707", "399802", "399803", "399804", "399805", "399806", "399807", "399808", "399809", "399810", "399811", "399812", "399813", "399814", "399817", "399901", "399903", "399904", "399905", "399908", "399909", "399910", "399911", "399912", "399913", "399914", "399917", "399918", "399919", "399922", "399925", "399928", "399931", "399932", "399933", "399934", "399935", "399939", "399944", "399950", "399951", "399952", "399957", "399958", "399959", "399961", "399963", "399964", "399965", "399966", "399967", "399969", "399970", "399971", "399972", "399973", "399974", "399975", "399976", "399977", "399978", "399979", "399982", "399983", "399986", "399987", "399989", "399990", "399991", "399992", "399993", "399994", "399995", "399996", "399997", "399998", "501000", "501001", "501002", "501003", "501005", "501006", "501007", "501008", "501009", "501010", "501011", "501012", "501015", "501016", "501017", "501018", "501019", "501020", "501021", "501022", "501023", "501025", "501026", "501027", "501027", "501028", "501029", "501029", "501030", "501031", "501032", "501035", "501036", "501037", "501038", "501043", "501045", "501046", "501050", "501106", "501300", "501301", "501302", "501303", "502000", "502001", "502002", "502003", "502004", "502005", "502006", "502007", "502008", "502010", "502011", "502012", "502013", "502014", "502015", "502016", "502017", "502018", "502020", "502021", "502022", "502023", "502024", "502025", "502026", "502027", "502028", "502030", "502031", "502032", "502036", "502037", "502038", "502040", "502041", "502042", "502048", "502049", "502050", "502053", "502054", "502055", "502056", "502057", "502058", "505888", "510010", "510020", "510030", "510050", "510060", "510070", "510090", "510110", "510120", "510130", "510150", "510160", "510170", "510180", "510190", "510210", "510220", "510230", "510260", "510270", "510280", "510290", "510300", "510310", "510330", "510360", "510410", "510420", "510430", "510440", "510500", "510510", "510520", "510560", "510580", "510630", "510650", "510660", "510680", "510710", "510810", "510880", "510900", "511010", "511220", "511230", "511230", "511260", "511600", "511620", "511650", "511660", "511670", "511680", "511690", "511700", "511760", "511770", "511800", "511810", "511820", "511830", "511850", "511860", "511880", "511890", "511900", "511910", "511920", "511930", "511950", "511960", "511970", "511980", "511990", "512000", "512010", "512070", "512100", "512120", "512200", "512210", "512220", "512230", "512300", "512310", "512330", "512340", "512400", "512500", "512510", "512550", "512560", "512570", "512580", "512600", "512610", "512640", "512660", "512680", "512700", "512800", "512810", "512880", "512900", "512990", "513030", "513050", "513100", "513500", "513600", "513660", "518800", "518801", "518802", "518805", "518880", "518881", "518882", "518885", "600000", "600001", "600002", "600003", "600004", "600005", "600006", "600007", "600008", "600009", "600010", "600011", "600012", "600015", "600016", "600017", "600018", "600019", "600020", "600021", "600022", "600023", "600025", "600026", "600027", "600028", "600029", "600030", "600031", "600033", "600035", "600036", "600037", "600038", "600039", "600048", "600050", "600051", "600052", "600053", "600054", "600055", "600056", "600057", "600058", "600059", "600060", "600061", "600062", "600063", "600064", "600065", "600066", "600067", "600068", "600069", "600070", "600071", "600072", "600073", "600074", "600075", "600076", "600077", "600078", "600079", "600080", "600081", "600082", "600083", "600084", "600085", "600086", "600087", "600088", "600089", "600090", "600091", "600092", "600093", "600094", "600095", "600096", "600097", "600098", "600099", "600100", "600101", "600102", "600103", "600104", "600105", "600106", "600107", "600108", "600109", "600110", "600111", "600112", "600113", "600114", "600115", "600116", "600117", "600118", "600119", "600120", "600121", "600122", "600123", "600125", "600126", "600127", "600128", "600129", "600130", "600131", "600132", "600133", "600135", "600136", "600137", "600138", "600139", "600141", "600143", "600145", "600146", "600148", "600149", "600150", "600151", "600152", "600153", "600155", "600156", "600157", "600158", "600159", "600160", "600161", "600162", "600163", "600165", "600166", "600167", "600168", "600169", "600170", "600171", "600172", "600173", "600175", "600176", "600177", "600178", "600179", "600180", "600181", "600182", "600183", "600184", "600185", "600186", "600187", "600188", "600189", "600190", "600191", "600192", "600193", "600195", "600196", "600197", "600198", "600199", "600200", "600201", "600202", "600203", "600205", "600206", "600207", "600208", "600209", "600210", "600211", "600212", "600213", "600215", "600216", "600217", "600218", "600219", "600220", "600221", "600222", "600223", "600225", "600226", "600227", "600228", "600229", "600230", "600231", "600232", "600233", "600234", "600235", "600236", "600237", "600238", "600239", "600240", "600241", "600242", "600243", "600246", "600247", "600248", "600249", "600250", "600251", "600252", "600253", "600255", "600256", "600257", "600258", "600259", "600260", "600261", "600262", "600263", "600265", "600266", "600267", "600268", "600269", "600270", "600271", "600272", "600273", "600275", "600276", "600277", "600278", "600279", "600280", "600281", "600282", "600283", "600284", "600285", "600286", "600287", "600288", "600289", "600290", "600291", "600292", "600293", "600295", "600296", "600297", "600298", "600299", "600300", "600301", "600302", "600303", "600305", "600306", "600307", "600308", "600309", "600310", "600311", "600312", "600313", "600315", "600316", "600317", "600318", "600319", "600320", "600321", "600322", "600323", "600325", "600326", "600327", "600328", "600329", "600330", "600331", "600332", "600333", "600335", "600336", "600337", "600338", "600339", "600340", "600343", "600345", "600346", "600348", "600350", "600351", "600352", "600353", "600354", "600355", "600356", "600357", "600358", "600359", "600360", "600361", "600362", "600363", "600365", "600366", "600367", "600368", "600369", "600370", "600371", "600372", "600373", "600375", "600376", "600377", "600378", "600379", "600380", "600381", "600382", "600383", "600385", "600386", "600387", "600388", "600389", "600390", "600391", "600392", "600393", "600395", "600396", "600397", "600398", "600399", "600400", "600401", "600403", "600405", "600406", "600408", "600409", "600410", "600415", "600416", "600418", "600419", "600420", "600421", "600422", "600423", "600425", "600426", "600428", "600429", "600432", "600433", "600435", "600436", "600438", "600439", "600444", "600446", "600448", "600449", "600452", "600455", "600456", "600458", "600459", "600460", "600461", "600462", "600463", "600466", "600467", "600468", "600469", "600470", "600472", "600475", "600476", "600477", "600478", "600479", "600480", "600481", "600482", "600483", "600485", "600486", "600487", "600488", "600489", "600490", "600491", "600493", "600495", "600496", "600497", "600498", "600499", "600500", "600501", "600502", "600503", "600505", "600506", "600507", "600508", "600509", "600510", "600511", "600512", "600513", "600515", "600516", "600517", "600518", "600519", "600520", "600521", "600522", "600523", "600525", "600526", "600527", "600528", "600529", "600530", "600531", "600532", "600533", "600535", "600536", "600537", "600538", "600539", "600540", "600543", "600545", "600546", "600547", "600547", "600548", "600549", "600550", "600551", "600552", "600553", "600555", "600556", "600557", "600558", "600559", "600560", "600561", "600562", "600563", "600565", "600566", "600567", "600568", "600569", "600570", "600571", "600572", "600573", "600575", "600576", "600577", "600578", "600579", "600580", "600581", "600582", "600583", "600584", "600585", "600586", "600587", "600588", "600589", "600590", "600591", "600592", "600593", "600594", "600595", "600596", "600597", "600598", "600599", "600600", "600601", "600602", "600603", "600604", "600605", "600606", "600607", "600608", "600609", "600610", "600611", "600612", "600613", "600614", "600615", "600616", "600617", "600618", "600619", "600620", "600621", "600622", "600623", "600624", "600625", "600626", "600627", "600628", "600629", "600630", "600631", "600632", "600633", "600634", "600635", "600636", "600637", "600638", "600639", "600640", "600641", "600642", "600643", "600644", "600645", "600646", "600647", "600648", "600649", "600650", "600651", "600652", "600653", "600654", "600655", "600656", "600657", "600658", "600659", "600660", "600661", "600662", "600663", "600664", "600665", "600666", "600667", "600668", "600669", "600670", "600671", "600672", "600673", "600674", "600675", "600676", "600677", "600678", "600679", "600680", "600681", "600682", "600683", "600684", "600685", "600686", "600687", "600688", "600689", "600690", "600691", "600692", "600693", "600694", "600695", "600696", "600696", "600697", "600698", "600699", "600700", "600701", "600702", "600703", "600704", "600705", "600706", "600707", "600708", "600709", "600710", "600711", "600712", "600713", "600714", "600715", "600716", "600717", "600718", "600719", "600720", "600721", "600722", "600723", "600724", "600725", "600726", "600727", "600728", "600729", "600730", "600731", "600732", "600733", "600733", "600734", "600735", "600736", "600737", "600738", "600739", "600740", "600741", "600742", "600743", "600744", "600745", "600746", "600747", "600748", "600749", "600750", "600751", "600752", "600753", "600754", "600755", "600756", "600757", "600758", "600759", "600760", "600761", "600762", "600763", "600764", "600765", "600766", "600767", "600768", "600769", "600770", "600771", "600772", "600773", "600774", "600775", "600776", "600777", "600778", "600779", "600780", "600781", "600782", "600783", "600784", "600785", "600786", "600787", "600788", "600789", "600790", "600791", "600792", "600793", "600794", "600795", "600796", "600797", "600798", "600799", "600800", "600801", "600802", "600803", "600803", "600804", "600805", "600806", "600807", "600808", "600809", "600810", "600811", "600812", "600813", "600814", "600815", "600816", "600817", "600818", "600819", "600820", "600821", "600822", "600823", "600824", "600825", "600826", "600827", "600828", "600829", "600830", "600831", "600832", "600833", "600834", "600835", "600836", "600837", "600838", "600839", "600840", "600841", "600842", "600843", "600844", "600844", "600845", "600846", "600847", "600848", "600849", "600850", "600851", "600852", "600853", "600854", "600855", "600856", "600857", "600858", "600859", "600860", "600861", "600862", "600863", "600864", "600865", "600866", "600867", "600868", "600869", "600870", "600871", "600872", "600873", "600874", "600875", "600876", "600877", "600878", "600879", "600880", "600881", "600882", "600883", "600884", "600885", "600886", "600887", "600888", "600889", "600890", "600891", "600892", "600893", "600894", "600895", "600896", "600897", "600898", "600899", "600900", "600901", "600901", "600903", "600908", "600909", "600917", "600919", "600926", "600933", "600936", "600939", "600958", "600959", "600960", "600961", "600962", "600963", "600965", "600966", "600967", "600969", "600970", "600971", "600973", "600975", "600976", "600977", "600978", "600979", "600980", "600981", "600982", "600983", "600984", "600985", "600986", "600987", "600988", "600990", "600991", "600992", "600993", "600995", "600996", "600997", "600998", "600999", "601000", "601001", "601002", "601003", "601005", "601005", "601006", "601007", "601008", "601009", "601010", "601011", "601012", "601015", "601016", "601018", "601019", "601020", "601021", "601028", "601038", "601058", "601069", "601086", "601088", "601098", "601099", "601100", "601101", "601106", "601107", "601108", "601111", "601113", "601116", "601117", "601118", "601126", "601127", "601128", "601137", "601139", "601155", "601158", "601163", "601166", "601168", "601169", "601177", "601179", "601186", "601188", "601198", "601199", "601200", "601208", "601211", "601212", "601216", "601218", "601222", "601225", "601226", "601228", "601229", "601231", "601233", "601238", "601258", "601268", "601288", "601299", "601311", "601313", "601318", "601326", "601328", "601333", "601336", "601339", "601360", "601366", "601368", "601369", "601375", "601377", "601388", "601390", "601398", "601500", "601515", "601518", "601519", "601555", "601558", "601566", "601567", "601579", "601588", "601595", "601599", "601600", "601601", "601607", "601608", "601611", "601616", "601618", "601619", "601628", "601633", "601636", "601666", "601668", "601669", "601677", "601678", "601688", "601689", "601699", "601700", "601717", "601718", "601727", "601766", "601777", "601788", "601789", "601798", "601799", "601800", "601801", "601808", "601811", "601818", "601828", "601838", "601857", "601858", "601866", "601872", "601877", "601878", "601880", "601881", "601882", "601886", "601888", "601890", "601898", "601899", "601900", "601901", "601908", "601918", "601919", "601928", "601929", "601933", "601939", "601949", "601952", "601958", "601965", "601966", "601968", "601969", "601985", "601988", "601989", "601991", "601992", "601996", "601997", "601998", "601999", "603000", "603001", "603002", "603003", "603005", "603006", "603007", "603008", "603009", "603010", "603011", "603012", "603015", "603016", "603017", "603018", "603019", "603020", "603021", "603022", "603023", "603025", "603026", "603027", "603028", "603029", "603030", "603031", "603032", "603033", "603035", "603036", "603037", "603038", "603039", "603040", "603041", "603042", "603043", "603050", "603055", "603056", "603058", "603059", "603059", "603060", "603063", "603066", "603067", "603069", "603076", "603077", "603078", "603079", "603080", "603081", "603083", "603085", "603086", "603088", "603089", "603090", "603096", "603098", "603099", "603100", "603101", "603103", "603106", "603108", "603110", "603111", "603113", "603116", "603117", "603118", "603123", "603126", "603127", "603128", "603129", "603131", "603133", "603136", "603138", "603139", "603156", "603156", "603157", "603158", "603159", "603160", "603161", "603165", "603166", "603167", "603168", "603169", "603177", "603178", "603179", "603180", "603181", "603183", "603186", "603188", "603189", "603196", "603197", "603198", "603199", "603200", "603203", "603208", "603218", "603222", "603223", "603225", "603226", "603227", "603228", "603229", "603232", "603233", "603238", "603239", "603258", "603260", "603266", "603268", "603269", "603277", "603278", "603283", "603286", "603288", "603289", "603298", "603299", "603300", "603303", "603305", "603306", "603308", "603309", "603311", "603313", "603315", "603316", "603318", "603319", "603320", "603321", "603322", "603323", "603326", "603328", "603329", "603330", "603331", "603333", "603335", "603336", "603337", "603338", "603339", "603345", "603355", "603356", "603357", "603358", "603359", "603360", "603363", "603365", "603366", "603367", "603368", "603369", "603377", "603378", "603380", "603383", "603385", "603386", "603387", "603388", "603389", "603393", "603396", "603398", "603399", "603399", "603416", "603421", "603429", "603444", "603456", "603458", "603466", "603477", "603488", "603496", "603499", "603500", "603501", "603505", "603506", "603507", "603508", "603515", "603516", "603516", "603517", "603518", "603519", "603520", "603527", "603528", "603533", "603535", "603536", "603538", "603555", "603556", "603557", "603558", "603559", "603566", "603567", "603568", "603569", "603577", "603578", "603579", "603580", "603585", "603586", "603588", "603589", "603595", "603598", "603599", "603600", "603601", "603602", "603603", "603605", "603606", "603607", "603608", "603609", "603611", "603612", "603615", "603616", "603617", "603618", "603619", "603626", "603628", "603630", "603633", "603636", "603637", "603638", "603639", "603648", "603655", "603656", "603658", "603659", "603660", "603661", "603663", "603665", "603667", "603668", "603669", "603676", "603677", "603678", "603679", "603680", "603680", "603683", "603685", "603686", "603688", "603689", "603690", "603696", "603698", "603699", "603701", "603703", "603707", "603708", "603709", "603709", "603711", "603712", "603716", "603717", "603718", "603721", "603722", "603725", "603726", "603727", "603728", "603729", "603730", "603737", "603738", "603757", "603758", "603766", "603767", "603768", "603776", "603777", "603778", "603779", "603787", "603788", "603789", "603797", "603798", "603799", "603800", "603801", "603803", "603806", "603808", "603809", "603811", "603813", "603816", "603817", "603818", "603819", "603822", "603823", "603825", "603826", "603828", "603829", "603833", "603838", "603839", "603843", "603848", "603855", "603856", "603858", "603859", "603860", "603861", "603866", "603868", "603869", "603871", "603871", "603877", "603878", "603879", "603880", "603881", "603882", "603883", "603885", "603886", "603887", "603888", "603889", "603890", "603895", "603896", "603898", "603899", "603900", "603901", "603903", "603906", "603908", "603909", "603912", "603916", "603917", "603918", "603919", "603920", "603922", "603926", "603928", "603929", "603933", "603936", "603937", "603938", "603939", "603955", "603958", "603959", "603960", "603963", "603966", "603968", "603969", "603970", "603976", "603977", "603978", "603979", "603980", "603985", "603986", "603987", "603988", "603989", "603990", "603991", "603993", "603996", "603997", "603998", "603999", "751038", "900901", "900902", "900903", "900904", "900905", "900906", "900907", "900908", "900909", "900910", "900911", "900912", "900913", "900914", "900915", "900916", "900917", "900918", "900919", "900920", "900921", "900921", "900922", "900923", "900924", "900925", "900926", "900927", "900928", "900929", "900930", "900932", "900933", "900934", "900935", "900936", "900937", "900938", "900939", "900940", "900941", "900942", "900943", "900945", "900946", "900947", "900948", "900950", "900951", "900952", "900953", "900955", "900956", "900957", "991002", "991003", "991004", "991006", "991007", "991008", "991009", "991010", "991011", "991013", "991014", "991015", "991016", "991017", "991018", "991019", "991020", "991021", "991022", "991023", "991024", "991025", "991026", "991027", "991028", "991029", "991030", "991031", "991032", "991033", "991034", "991035", "991036", "991037", "991038", "991039", "991040", "991041", "991042", "991043", "991044", "991045", "991046", "991047", "991135", "991136", "991255", "991256", "993028", "993029", "993030", "993031", "993032", "993033", "993034", "993035", "993038", "993039", "993040", "993041", "993042", "993043", "993045", "993046", "993047", "993048", "993049", "993050", "993051", "993052", "993053", "993054", "993055", "993056", "993057", "993058", "993059", "993060", "993061", "993062", "993063", "993064", "993065", "993066", "993067", "993068", "993069", "993070", "993074", "993075", "993120", "993124", "993130", "993139", "993140", "993141", "993144", "993305", "993386", "993405", "993505", "993583", "993585", "993586", "993587", "993591", "993592", "993597", "993601", "993610", "993611", "993625", "993645", "993646", "993665", "993666", "993667", "993670", "993695", "993703", "993706", "993707", "993708", "993732", "993736", "993738", "993742", "993745", "993751", "993752", "993756", "993758", "993759", "993761", "993798", "993801", "993806", "993885", "993926", "993927", "993928", "993929", "993930", "993931", "993932", "993933", "993935", "993936", "993937", "993938", "993939", "993949", "993950", "993951", "993952", "993953", "993954", "993956", "993957", "993959", "993960", "993961", "993962", "993963", "993965", "993966", "993967", "993968", "993969", "993970", "993971", "993972", "993973", "993974", "993975", "993976", "993977", "993978", "993979", "993980", "993995", "993996", "993997", "993998", "994002", "994005", "994011", "994012", "994035", "994050", "994070", "994079", "994086", "994090", "994093", "994168", "994173", "994192", "994194", "994219", "994222", "994225", "994242", "994251", "994254", "994256", "994266", "994268", "994269", "994309", "994312", "994314", "994316", "994317", "994318", "994322", "994323", "994324", "994325", "994326", "994327", "994328", "994329", "994330", "994337", "994340", "994342", "994343", "994345", "994351", "994352", "994353", "994357", "994362", "994375", "994376", "994377", "994379", "994380", "994383", "994389", "994390", "994391", "994394", "994396", "994397", "994400", "994402", "998000", "998001", "998002", "998003"]} -------------------------------------------------------------------------------- /easyquotation/tencent.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import re 3 | from datetime import datetime 4 | 5 | from . import basequotation 6 | 7 | 8 | class Tencent(basequotation.BaseQuotation): 9 | """腾讯免费行情获取""" 10 | 11 | grep_stock_code = re.compile(r"(?<=_)\w+") 12 | max_num = 60 13 | 14 | @property 15 | def stock_api(self) -> str: 16 | return "http://qt.gtimg.cn/q=" 17 | 18 | def format_response_data(self, rep_data, prefix=False): 19 | stocks_detail = "".join(rep_data) 20 | stock_details = stocks_detail.split(";") 21 | stock_dict = dict() 22 | for stock_detail in stock_details: 23 | stock = stock_detail.split("~") 24 | if len(stock) <= 49: 25 | continue 26 | stock_code = ( 27 | self.grep_stock_code.search(stock[0]).group() 28 | if prefix 29 | else stock[2] 30 | ) 31 | stock_dict[stock_code] = { 32 | "name": stock[1], 33 | "code": stock_code, 34 | "now": float(stock[3]), 35 | "close": float(stock[4]), 36 | "open": float(stock[5]), 37 | "volume": float(stock[6]) * 100, 38 | "bid_volume": int(stock[7]) * 100, 39 | "ask_volume": float(stock[8]) * 100, 40 | "bid1": float(stock[9]), 41 | "bid1_volume": int(stock[10]) * 100, 42 | "bid2": float(stock[11]), 43 | "bid2_volume": int(stock[12]) * 100, 44 | "bid3": float(stock[13]), 45 | "bid3_volume": int(stock[14]) * 100, 46 | "bid4": float(stock[15]), 47 | "bid4_volume": int(stock[16]) * 100, 48 | "bid5": float(stock[17]), 49 | "bid5_volume": int(stock[18]) * 100, 50 | "ask1": float(stock[19]), 51 | "ask1_volume": int(stock[20]) * 100, 52 | "ask2": float(stock[21]), 53 | "ask2_volume": int(stock[22]) * 100, 54 | "ask3": float(stock[23]), 55 | "ask3_volume": int(stock[24]) * 100, 56 | "ask4": float(stock[25]), 57 | "ask4_volume": int(stock[26]) * 100, 58 | "ask5": float(stock[27]), 59 | "ask5_volume": int(stock[28]) * 100, 60 | "最近逐笔成交": stock[29], # 换成英文 61 | "datetime": datetime.strptime(stock[30], "%Y%m%d%H%M%S"), 62 | "涨跌": float(stock[31]), # 换成英文 63 | "涨跌(%)": float(stock[32]), # 换成英文 64 | "high": float(stock[33]), 65 | "low": float(stock[34]), 66 | "价格/成交量(手)/成交额": stock[35], # 换成英文 67 | "成交量(手)": int(stock[36]) * 100, # 换成英文 68 | "成交额(万)": float(stock[37]) * 10000, # 换成英文 69 | "turnover": float(stock[38]) if stock[38] != "" else None, 70 | "PE": float(stock[39]) if stock[39] != "" else None, 71 | "unknown": stock[40], 72 | "high_2": float(stock[41]), # 意义不明 73 | "low_2": float(stock[42]), # 意义不明 74 | "振幅": float(stock[43]), # 换成英文 75 | "流通市值": float(stock[44]) if stock[44] != "" else None, # 换成英文 76 | "总市值": float(stock[45]) if stock[44] != "" else None, # 换成英文 77 | "PB": float(stock[46]), 78 | "涨停价": float(stock[47]), # 换成英文 79 | "跌停价": float(stock[48]), # 换成英文 80 | } 81 | return stock_dict 82 | -------------------------------------------------------------------------------- /easyquotation/timekline.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | """ 3 | # pylint: disable=line-too-long 4 | url = "http://data.gtimg.cn/flashdata/hushen/minute/sz000001.js?maxage=110&0.28163905744440854" 5 | """ 6 | 7 | import re 8 | 9 | import easyutils 10 | 11 | from . import basequotation 12 | 13 | 14 | class TimeKline(basequotation.BaseQuotation): 15 | """腾讯免费行情获取""" 16 | 17 | max_num = 1 18 | 19 | @property 20 | def stock_api(self) -> str: 21 | return "http://data.gtimg.cn/flashdata/hushen/minute/" 22 | 23 | def _gen_stock_prefix(self, stock_codes): 24 | return [ 25 | easyutils.stock.get_stock_type(code) + code[-6:] + ".js" 26 | for code in stock_codes 27 | ] 28 | 29 | def _fetch_stock_data(self, stock_list): 30 | """因为 timekline 的返回没有带对应的股票代码,所以要手动带上""" 31 | res = super()._fetch_stock_data(stock_list) 32 | 33 | with_stock = [] 34 | for stock, resp in zip(stock_list, res): 35 | if resp is not None: 36 | with_stock.append((stock, resp)) 37 | return with_stock 38 | 39 | def format_response_data(self, rep_data, **kwargs): 40 | stock_dict = dict() 41 | for stock_code, stock_detail in rep_data: 42 | # pylint: disable=line-too-long 43 | # res like ['min_data="', 'date:180413', '0930 11.64 29727', '0931 11.65 52410'] 44 | res = re.split(r"\\n\\\n", stock_detail) 45 | date = "20{}".format(res[1][-6:]) 46 | time_data = list( 47 | d.split() for d in res[2:] if re.match(r"\d{4}", d) 48 | ) 49 | stock_dict[stock_code] = {"date": date, "time_data": time_data} 50 | return stock_dict 51 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | ignore_missing_imports = True 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -i http://mirrors.aliyun.com/pypi/simple/ 2 | --trusted-host mirrors.aliyun.com 3 | certifi==2018.4.16 4 | chardet==3.0.4 5 | cssselect==1.0.3; python_version != '3.3.*' 6 | easyutils==0.1.7 7 | idna==2.7 8 | lxml==4.2.3 9 | pyquery==1.4.0; python_version != '3.0.*' 10 | requests==2.19.1 11 | six==1.11.0 12 | urllib3==1.23; python_version != '3.1.*' 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | from setuptools import setup 3 | 4 | long_desc = """ 5 | easyquotation 6 | =============== 7 | 8 | * easy to use to get stock info in China Stock 9 | 10 | Installation 11 | -------------- 12 | 13 | pip install easyquotation 14 | 15 | Upgrade 16 | --------------- 17 | 18 | pip install easyquotation --upgrade 19 | 20 | Quick Start 21 | -------------- 22 | 23 | :: 24 | 25 | import easyquotation 26 | 27 | 28 | #### 选择 sina 行情 29 | 30 | ```python 31 | quotation = easyquotation.use('sina') 32 | ``` 33 | 34 | #### 获取所有股票行情 35 | 36 | ```python 37 | quotation.all 38 | ``` 39 | 40 | **return** 41 | 42 | ```python 43 | {'000159': {'name': '国际实业', # 股票名 44 | 'buy': '8.87', # 竞买价 45 | 'sell': '8.88', # 竞卖价 46 | 'now': '8.88', # 现价 47 | 'open': '8.99', # 开盘价 48 | 'close': '8.96', # 昨日收盘价 49 | 'high': '9.15', # 今日最高价 50 | 'low': '8.83', # 今日最低价 51 | 'turnover': '22545048', # 交易股数 52 | 'volume': '202704887.74', # 交易金额 53 | 'ask1': '8.88', # 卖一价 54 | 'ask1_volume': '111900', # 卖一量 55 | 'ask2': '8.89', 56 | 'ask2_volume': '54700', 57 | 'bid1': '8.87', # 买一价 58 | 'bid1_volume': '21800', # 买一量 59 | ... 60 | 'bid2': '8.86', 61 | 'bid2_volume': '78400', 62 | 'date': '2016-02-19', 63 | 'time': '14:30:00', 64 | ...}, 65 | ...... 66 | } 67 | ``` 68 | 69 | #### 选择 leverfun 免费十档行情 70 | 71 | ``` 72 | quotation = easyquotation.use('lf') # ['leverfun', 'lf'] 73 | ``` 74 | 75 | #### 获取十档行情 76 | 77 | ##### 单只股票 78 | 79 | ``` 80 | quotation.stocks('162411') 81 | ``` 82 | 83 | ##### 多只股票 84 | 85 | ``` 86 | quotation.stocks(['000001', '162411']) 87 | ``` 88 | 89 | **return** 90 | 91 | ```python 92 | {'000159': {'buy': '8.87', # 竞买价 93 | 'sell': '8.88', # 竞卖价 94 | 'now': '8.88', # 现价 95 | 'close': '8.96', # 昨日收盘价 96 | 'ask1': '8.88', # 卖一价 97 | 'ask1_volume': '111900', # 卖一量 98 | 'ask2': '8.89', 99 | 'ask2_volume': '54700', 100 | 'bid1': '8.87', # 买一价 101 | 'bid1_volume': '21800', # 买一量 102 | ... 103 | 'bid2': '8.86', 104 | 'bid2_volume': '78400', 105 | ...}, 106 | ...... 107 | } 108 | ``` 109 | 110 | #### 选择 jsl 行情 111 | 112 | ``` 113 | quotation = easyquotation.use('jsl') # ['jsl'] 114 | ``` 115 | 116 | ##### 获取分级基金信息 117 | 118 | ``` 119 | quotation.funda() # 参数可选择利率、折价率、交易量、有无下折、是否永续来过滤 120 | 121 | quotation.fundb() # 参数如上 122 | ``` 123 | 124 | *****return** 125 | 126 | ``` 127 | { 150020: 128 | {'abrate': '5:5', 129 | 'calc_info': None, 130 | 'coupon_descr': '+3.0%', 131 | 'coupon_descr_s': '+3.0%', 132 | 'fund_descr': '每年第一个工作日定折,无下折,A不参与上折,净值<1元无定折', 133 | 'funda_amount': 178823, 134 | 'funda_amount_increase': '0', 135 | 'funda_amount_increase_rt': '0.00%', 136 | 'funda_base_est_dis_rt': '2.27%', 137 | 'funda_base_est_dis_rt_t1': '2.27%', 138 | 'funda_base_est_dis_rt_t2': '-0.34%', 139 | 'funda_base_est_dis_rt_tip': '', 140 | 'funda_base_fund_id': '163109', 141 | 'funda_coupon': '5.75', 142 | 'funda_coupon_next': '4.75', 143 | 'funda_current_price': '0.783', 144 | 'funda_discount_rt': '24.75%', 145 | 'funda_id': '150022', 146 | 'funda_increase_rt': '0.00%', 147 | 'funda_index_id': '399001', 148 | 'funda_index_increase_rt': '0.00%', 149 | 'funda_index_name': '深证成指', 150 | 'funda_left_year': '永续', 151 | 'funda_lower_recalc_rt': '1.82%', 152 | 'funda_name': '深成指A', 153 | 'funda_nav_dt': '2015-09-14', 154 | 'funda_profit_rt': '7.74%', 155 | 'funda_profit_rt_next': '6.424%', 156 | 'funda_value': '1.0405', 157 | 'funda_volume': '0.00', 158 | 'fundb_upper_recalc_rt': '244.35%', 159 | 'fundb_upper_recalc_rt_info': '深成指A不参与上折', 160 | 'last_time': '09:18:22', 161 | 'left_recalc_year': '0.30411', 162 | 'lower_recalc_profit_rt': '-', 163 | 'next_recalc_dt': '2016-01-04', 164 | 'owned': 0, 165 | 'status_cd': 'N'}>'}} 166 | ``` 167 | 168 | 169 | #### 更新股票代码 170 | 171 | ``` 172 | easyquotation.update_stock_codes() 173 | ``` 174 | """ 175 | 176 | setup( 177 | name="easyquotation", 178 | version="0.5.13", 179 | description="A utility for Fetch China Stock Info", 180 | long_description=long_desc, 181 | author="shidenggui", 182 | author_email="longlyshidenggui@gmail.com", 183 | license="BSD", 184 | url="https://github.com/shidenggui/easyquotation", 185 | keywords="China stock trade", 186 | install_requires=[ 187 | "requests", 188 | "aiohttp>=1.1.1", 189 | "yarl", 190 | "six", 191 | "easyutils", 192 | ], 193 | classifiers=[ 194 | "Development Status :: 4 - Beta", 195 | "Programming Language :: Python :: 3.5", 196 | "License :: OSI Approved :: BSD License", 197 | ], 198 | packages=["easyquotation"], 199 | package_data={"": ["*.conf"]}, 200 | ) 201 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | 3 | pytest 4 | pytest-cov 5 | 6 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | -------------------------------------------------------------------------------- /tests/test_easyquotation.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import unittest 3 | 4 | import easyquotation 5 | 6 | 7 | class TestEasyquotation(unittest.TestCase): 8 | def test_stock_code_with_prefix(self): 9 | cases = ["sina", "qq"] 10 | for src in cases: 11 | q = easyquotation.use(src) 12 | data = q.all_market 13 | for k in data.keys(): 14 | self.assertRegex(k, r"(sh|sz)\d{6}") 15 | 16 | def test_all(self): 17 | cases = ["sina", "qq"] 18 | for src in cases: 19 | q = easyquotation.use(src) 20 | data = q.all 21 | for k in data.keys(): 22 | self.assertRegex(k, r"\d{6}") 23 | 24 | 25 | class TestHqouteQuotatin(unittest.TestCase): 26 | MOCK_RESPONSE_DATA = 'v_r_hk00700="100~腾讯控股~00700~409.600~412.200~414.000~41115421.0~0~0~409.600~0~0~0~0~0~0~0~0~0~409.600~0~0~0~0~0~0~0~0~0~41115421.0~2018/03/29 16:08:11~-2.600~-0.63~417.000~405.200~409.600~41115421.0~16899465578.300~0~44.97~~0~0~2.86~38909.443~38909.443~TENCENT~0.21~476.600~222.400~0.40~0~0~0~0~0~0~42.25~12.70~"; v_r_hk00980="100~联华超市~00980~2.390~2.380~2.380~825000.0~0~0~2.390~0~0~0~0~0~0~0~0~0~2.390~0~0~0~0~0~0~0~0~0~825000.0~2018/03/29 16:08:11~0.010~0.42~2.440~2.330~2.390~825000.0~1949820.000~0~-5.38~~0~0~4.62~8.905~26.758~LIANHUA~0.00~4.530~2.330~1.94~0~0~0~0~0~0~-0.01~0.94~";' 27 | 28 | def setUp(self): 29 | self._obj = easyquotation.use("hkquote") 30 | 31 | def test_format_response_data(self): 32 | excepted = { 33 | "00700": { 34 | "amount": 41115421.0, 35 | "high": 417.0, 36 | "lastPrice": 412.2, 37 | "lotSize": 100.0, 38 | "low": 405.2, 39 | "name": "腾讯控股", 40 | "openPrice": 414.0, 41 | "price": 409.6, 42 | "time": "2018/03/29 16:08:11", 43 | }, 44 | "00980": { 45 | "amount": 825000.0, 46 | "high": 2.44, 47 | "lastPrice": 2.38, 48 | "lotSize": 100.0, 49 | "low": 2.33, 50 | "name": "联华超市", 51 | "openPrice": 2.38, 52 | "price": 2.39, 53 | "time": "2018/03/29 16:08:11", 54 | }, 55 | } 56 | result = self._obj.format_response_data(self.MOCK_RESPONSE_DATA) 57 | self.assertDictEqual(result, excepted) 58 | 59 | 60 | class TestDayklineQuotatin(unittest.TestCase): 61 | MOCK_RESPONSE_DATA = [ 62 | 'kline_dayqfq={"code":0,"msg":"","data":{"hk00001":{"qfqday":[["2018-04-09","91.00","91.85","93.50","91.00","8497462.00"]],"qt":{"hk00001":["100","\u957f\u548c","00001","91.850","91.500","91.000","8497462.0","0","0","91.850","0","0","0","0","0","0","0","0","0","91.850","0","0","0","0","0","0","0","0","0","8497462.0","2018\/04\/09 16:08:10","0.350","0.38","93.500","91.000","91.850","8497462.0","781628889.560","0","10.09","","0","0","2.73","3543.278","3543.278","CKH HOLDINGS","3.10","108.900","91.000","1.89","0","0","0","0","0","0","7.67","0.10",""],"market":["2018-04-09 22:36:01|HK_close_\u5df2\u6536\u76d8|SH_close_\u5df2\u6536\u76d8|SZ_close_\u5df2\u6536\u76d8|US_open_\u4ea4\u6613\u4e2d|SQ_close_\u5df2\u4f11\u5e02|DS_close_\u5df2\u4f11\u5e02|ZS_close_\u5df2\u4f11\u5e02"]},"prec":"91.50","vcm":"","version":"4"}}}' 63 | ] 64 | 65 | def setUp(self): 66 | self._obj = easyquotation.use("daykline") 67 | 68 | def test_format_response_data(self): 69 | excepted = { 70 | "00001": [ 71 | [ 72 | "2018-04-09", 73 | "91.00", 74 | "91.85", 75 | "93.50", 76 | "91.00", 77 | "8497462.00", 78 | ] 79 | ] 80 | } 81 | 82 | result = self._obj.format_response_data(self.MOCK_RESPONSE_DATA) 83 | self.assertDictEqual(result, excepted) 84 | 85 | 86 | if __name__ == "__main__": 87 | unittest.main() 88 | -------------------------------------------------------------------------------- /tests/test_sina.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | import unittest 4 | 5 | import easyquotation 6 | 7 | 8 | class TestSina(unittest.TestCase): 9 | MOCK_DATA = 'var hq_str_sz162411="华宝油气,0.489,0.488,0.491,0.492,0.488,0.490,0.491,133819867,65623147.285,2422992,0.490,4814611,0.489,2663142,0.488,1071900,0.487,357900,0.486,5386166,0.491,8094689,0.492,6087538,0.493,2132373,0.494,5180900,0.495,2019-03-12,15:00:03,00";\n' 10 | 11 | def setUp(self): 12 | self._sina = easyquotation.use("sina") 13 | 14 | def test_extract_stock_name(self): 15 | """ 16 | fix https://github.com/shidenggui/easyquotation/issues/51 17 | """ 18 | stock_name = self._sina.format_response_data(self.MOCK_DATA)["162411"][ 19 | "name" 20 | ] 21 | self.assertEqual(stock_name, "华宝油气") 22 | -------------------------------------------------------------------------------- /tests/test_timekline.py: -------------------------------------------------------------------------------- 1 | # coding:utf8 2 | import unittest 3 | from unittest import mock 4 | 5 | import easyquotation 6 | 7 | 8 | class TestTimeklineQuotation(unittest.TestCase): 9 | MOCK_RESPONSE_DATA = [ 10 | ( 11 | "000001", 12 | 'min_data="\\n\\\ndate:180413\\n\\\n0930 11.64 29727\\n\\\n0931 11.65 52410\\n\\\n";', 13 | ) 14 | ] 15 | 16 | def setUp(self): 17 | self._obj = easyquotation.use("timekline") 18 | 19 | @mock.patch( 20 | "easyquotation.timekline.basequotation.BaseQuotation._fetch_stock_data" 21 | ) 22 | def test_fetch_stock_data(self, mock_super_fetch): 23 | test_cases = [ 24 | (["000001"], ["test_data"], [("000001", "test_data")]), 25 | ( 26 | ["000001", "000002"], 27 | ["test_data", None], 28 | [("000001", "test_data")], 29 | ), 30 | ([], [], []), 31 | ] 32 | for stock_list, resp_data, expected in test_cases: 33 | mock_super_fetch.return_value = resp_data 34 | res = self._obj._fetch_stock_data(stock_list) 35 | self.assertListEqual(res, expected) 36 | 37 | def test_format_response_data(self): 38 | excepted = { 39 | "000001": { 40 | "date": "20180413", 41 | "time_data": [ 42 | ["0930", "11.64", "29727"], 43 | ["0931", "11.65", "52410"], 44 | ], 45 | } 46 | } 47 | 48 | result = self._obj.format_response_data(self.MOCK_RESPONSE_DATA) 49 | self.assertDictEqual(result, excepted) 50 | 51 | 52 | if __name__ == "__main__": 53 | unittest.main() 54 | --------------------------------------------------------------------------------