├── .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 | [](https://pypi.python.org/pypi/easyquotation)
4 | [](https://travis-ci.org/shidenggui/easyquotation)
5 | [](https://github.com/shidenggui/easyquotation/blob/master/LICENSE)
6 |
7 |
8 | 快速获取新浪/腾讯的全市场行情, 网络正常的情况下只需要 `200+ms`
9 |
10 | ### 前言
11 | * 获取新浪的免费实时行情
12 | * 获取腾讯财经的免费实时行情
13 | * 获取集思路的分级基金数据
14 | * 有兴趣的可以加群 `556050652` 一起讨论
15 | * 捐助:
16 |
17 |  
18 |
19 |
20 | ## 公众号
21 |
22 | 扫码关注“易量化”的微信公众号,不定时更新一些个人文章及与大家交流
23 |
24 | 
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 |
--------------------------------------------------------------------------------