emtl 0.1.2.dev2__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.bumpversion.cfg +1 -1
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.cookiecutterrc +2 -2
- emtl-0.1.5/.github/workflows/document.yml +38 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.github/workflows/github-actions.yml +46 -9
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.readthedocs.yml +1 -1
- emtl-0.1.5/CHANGELOG.rst +29 -0
- {emtl-0.1.2.dev2/src/emtl.egg-info → emtl-0.1.5}/PKG-INFO +25 -10
- {emtl-0.1.2.dev2 → emtl-0.1.5}/README.rst +3 -3
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/conf.py +4 -2
- emtl-0.1.5/docs/requirements.txt +1 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/usage.rst +2 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/setup.py +9 -9
- emtl-0.1.5/src/emtl/__init__.py +11 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl/_version.py +2 -2
- emtl-0.1.5/src/emtl/const.py +19 -0
- emtl-0.1.5/src/emtl/core.py +141 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl/tests/test_cli.py +1 -1
- emtl-0.1.5/src/emtl/tests/test_core.py +27 -0
- emtl-0.1.5/src/emtl/utils.py +51 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5/src/emtl.egg-info}/PKG-INFO +25 -10
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl.egg-info/SOURCES.txt +4 -0
- emtl-0.1.5/src/emtl.egg-info/requires.txt +4 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/tox.ini +1 -2
- emtl-0.1.2.dev2/CHANGELOG.rst +0 -13
- emtl-0.1.2.dev2/docs/requirements.txt +0 -2
- emtl-0.1.2.dev2/src/emtl/__init__.py +0 -9
- emtl-0.1.2.dev2/src/emtl/core.py +0 -8
- emtl-0.1.2.dev2/src/emtl/tests/test_core.py +0 -14
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.coveragerc +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.editorconfig +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.gitignore +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/.pre-commit-config.yaml +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/AUTHORS.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/CONTRIBUTING.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/LICENSE +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/ci/bootstrap.py +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/ci/requirements.txt +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/ci/templates/.github/workflows/github-actions.yml +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/authors.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/changelog.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/contributing.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/index.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/installation.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/readme.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/reference/emtl.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/reference/index.rst +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/docs/spelling_wordlist.txt +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/pyproject.toml +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/pytest.ini +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/setup.cfg +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl/__main__.py +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl/cli.py +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl/tests/__init__.py +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl.egg-info/dependency_links.txt +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl.egg-info/entry_points.txt +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl.egg-info/not-zip-safe +0 -0
- {emtl-0.1.2.dev2 → emtl-0.1.5}/src/emtl.egg-info/top_level.txt +0 -0
|
@@ -51,10 +51,10 @@ default_context:
|
|
|
51
51
|
sphinx_docs: "yes"
|
|
52
52
|
sphinx_docs_hosting: "https://emtl.readthedocs.io/"
|
|
53
53
|
sphinx_doctest: "no"
|
|
54
|
-
sphinx_theme: "
|
|
54
|
+
sphinx_theme: "alabaster"
|
|
55
55
|
test_matrix_separate_coverage: "yes"
|
|
56
56
|
tests_inside_package: "yes"
|
|
57
|
-
version: "0.1.
|
|
57
|
+
version: "0.1.4"
|
|
58
58
|
version_manager: "bump2version"
|
|
59
59
|
website: "riiy.gihub.io/emtl"
|
|
60
60
|
year_from: "2024"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Publish documentation
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: 3.11
|
|
18
|
+
architecture: x64
|
|
19
|
+
- name: install dependencies
|
|
20
|
+
run: |
|
|
21
|
+
python -mpip install --progress-bar=off -r ci/requirements.txt
|
|
22
|
+
python -mpip install Sphinx==7.2.6
|
|
23
|
+
virtualenv --version
|
|
24
|
+
pip --version
|
|
25
|
+
tox --version
|
|
26
|
+
pip list --format=freeze
|
|
27
|
+
- name: Build
|
|
28
|
+
env:
|
|
29
|
+
TOXPYTHON: 'python311'
|
|
30
|
+
run: >
|
|
31
|
+
tox -e docs -v
|
|
32
|
+
- name: Publish
|
|
33
|
+
uses: peaceiris/actions-gh-pages@v3
|
|
34
|
+
env:
|
|
35
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
36
|
+
with:
|
|
37
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
+
publish_dir: ./dist/docs
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
name: build
|
|
2
|
-
on:
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
pull_request:
|
|
7
|
+
branches:
|
|
8
|
+
- master
|
|
9
|
+
workflow_dispatch:
|
|
3
10
|
jobs:
|
|
4
11
|
test:
|
|
5
12
|
name: ${{ matrix.name }}
|
|
@@ -25,23 +32,47 @@ jobs:
|
|
|
25
32
|
python_arch: 'x64'
|
|
26
33
|
tox_env: 'py310-cover'
|
|
27
34
|
os: 'ubuntu-latest'
|
|
35
|
+
- name: 'py310-nocov (ubuntu)'
|
|
36
|
+
python: '3.10'
|
|
37
|
+
toxpython: 'python3.10'
|
|
38
|
+
python_arch: 'x64'
|
|
39
|
+
tox_env: 'py310-nocov'
|
|
40
|
+
os: 'ubuntu-latest'
|
|
41
|
+
- name: 'py310-cover (macos)'
|
|
42
|
+
python: '3.10'
|
|
43
|
+
toxpython: 'python3.10'
|
|
44
|
+
python_arch: 'x64'
|
|
45
|
+
tox_env: 'py310-cover'
|
|
46
|
+
os: 'macos-latest'
|
|
47
|
+
- name: 'py310-nocov (macos)'
|
|
48
|
+
python: '3.10'
|
|
49
|
+
toxpython: 'python3.10'
|
|
50
|
+
python_arch: 'x64'
|
|
51
|
+
tox_env: 'py310-nocov'
|
|
52
|
+
os: 'macos-latest'
|
|
28
53
|
- name: 'py311-cover (ubuntu)'
|
|
29
54
|
python: '3.11'
|
|
30
55
|
toxpython: 'python3.11'
|
|
31
56
|
python_arch: 'x64'
|
|
32
57
|
tox_env: 'py311-cover'
|
|
33
58
|
os: 'ubuntu-latest'
|
|
34
|
-
- name: '
|
|
35
|
-
python: '3.
|
|
36
|
-
toxpython: 'python3.
|
|
59
|
+
- name: 'py311-nocov (ubuntu)'
|
|
60
|
+
python: '3.11'
|
|
61
|
+
toxpython: 'python3.11'
|
|
37
62
|
python_arch: 'x64'
|
|
38
|
-
tox_env: '
|
|
63
|
+
tox_env: 'py311-nocov'
|
|
39
64
|
os: 'ubuntu-latest'
|
|
40
|
-
- name: '
|
|
41
|
-
python: '3.
|
|
42
|
-
toxpython: 'python3.
|
|
65
|
+
- name: 'py311-cover (macos)'
|
|
66
|
+
python: '3.11'
|
|
67
|
+
toxpython: 'python3.11'
|
|
68
|
+
python_arch: 'x64'
|
|
69
|
+
tox_env: 'py311-cover'
|
|
70
|
+
os: 'macos-latest'
|
|
71
|
+
- name: 'py311-nocov (macos)'
|
|
72
|
+
python: '3.11'
|
|
73
|
+
toxpython: 'python3.11'
|
|
43
74
|
python_arch: 'x64'
|
|
44
|
-
tox_env: '
|
|
75
|
+
tox_env: 'py311-nocov'
|
|
45
76
|
os: 'macos-latest'
|
|
46
77
|
steps:
|
|
47
78
|
- uses: actions/checkout@v4
|
|
@@ -61,6 +92,8 @@ jobs:
|
|
|
61
92
|
- name: test
|
|
62
93
|
env:
|
|
63
94
|
TOXPYTHON: '${{ matrix.toxpython }}'
|
|
95
|
+
EM_USERNAME: ${{ secrets.EM_USERNAME }}
|
|
96
|
+
EM_PASSWORD: ${{ secrets.EM_PASSWORD }}
|
|
64
97
|
run: >
|
|
65
98
|
tox -e ${{ matrix.tox_env }} -v
|
|
66
99
|
finish:
|
|
@@ -86,6 +119,8 @@ jobs:
|
|
|
86
119
|
env:
|
|
87
120
|
TOXPYTHON: 'python311'
|
|
88
121
|
PYTEST_ADDOPTS: '--cov-append'
|
|
122
|
+
EM_USERNAME: ${{ secrets.EM_USERNAME }}
|
|
123
|
+
EM_PASSWORD: ${{ secrets.EM_PASSWORD }}
|
|
89
124
|
run: >
|
|
90
125
|
PYTEST_ADDOPTS=--cov-append tox -e py310-cover -v
|
|
91
126
|
- uses: codecov/codecov-action@v4
|
|
@@ -95,3 +130,5 @@ jobs:
|
|
|
95
130
|
verbose: true
|
|
96
131
|
env:
|
|
97
132
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
133
|
+
EM_USERNAME: ${{ secrets.EM_USERNAME }}
|
|
134
|
+
EM_PASSWORD: ${{ secrets.EM_PASSWORD }}
|
emtl-0.1.5/CHANGELOG.rst
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
Changelog
|
|
3
|
+
=========
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
0.1.0 (2024-04-14)
|
|
7
|
+
------------------
|
|
8
|
+
|
|
9
|
+
* First release on PyPI.
|
|
10
|
+
|
|
11
|
+
0.1.1 (2024-04-16)
|
|
12
|
+
------------------
|
|
13
|
+
|
|
14
|
+
* Delete python3.8 python3.9 pypy.
|
|
15
|
+
|
|
16
|
+
0.1.2 (2024-04-18)
|
|
17
|
+
------------------
|
|
18
|
+
|
|
19
|
+
* add login && add asset position
|
|
20
|
+
|
|
21
|
+
0.1.3 (2024-04-19)
|
|
22
|
+
------------------
|
|
23
|
+
|
|
24
|
+
* update docs theme
|
|
25
|
+
|
|
26
|
+
0.1.5 (2024-04-24)
|
|
27
|
+
------------------
|
|
28
|
+
|
|
29
|
+
* update login refrence
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: emtl
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: 东方财富自动交易系统
|
|
5
5
|
Home-page: https://github.com/riiy/emtl
|
|
6
|
-
Author:
|
|
6
|
+
Author: Riiy
|
|
7
7
|
Author-email: riiyzhou@gmail.com
|
|
8
8
|
License: MIT
|
|
9
9
|
Project-URL: Documentation, https://emtl.readthedocs.io/
|
|
10
10
|
Project-URL: Changelog, https://emtl.readthedocs.io/en/latest/changelog.html
|
|
11
11
|
Project-URL: Issue Tracker, https://github.com/riiy/emtl/issues
|
|
12
|
-
Keywords: trade
|
|
12
|
+
Keywords: autotrade,trade,东方财富,股票,交易,交易机器人
|
|
13
13
|
Platform: UNKNOWN
|
|
14
|
-
Classifier: Development Status ::
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
17
|
Classifier: Operating System :: Unix
|
|
@@ -21,10 +21,9 @@ Classifier: Programming Language :: Python :: 3
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
25
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
25
|
Classifier: Topic :: Utilities
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
28
27
|
License-File: LICENSE
|
|
29
28
|
License-File: AUTHORS.rst
|
|
30
29
|
|
|
@@ -34,7 +33,7 @@ Overview
|
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
东方财富自动交易系统
|
|
38
37
|
|
|
39
38
|
* Free software: MIT license
|
|
40
39
|
|
|
@@ -85,14 +84,30 @@ Note, to combine the coverage data from all the tox environments run:
|
|
|
85
84
|
Changelog
|
|
86
85
|
=========
|
|
87
86
|
|
|
87
|
+
|
|
88
|
+
0.1.0 (2024-04-14)
|
|
89
|
+
------------------
|
|
90
|
+
|
|
91
|
+
* First release on PyPI.
|
|
92
|
+
|
|
88
93
|
0.1.1 (2024-04-16)
|
|
89
94
|
------------------
|
|
90
95
|
|
|
91
96
|
* Delete python3.8 python3.9 pypy.
|
|
92
97
|
|
|
93
|
-
0.1.
|
|
98
|
+
0.1.2 (2024-04-18)
|
|
94
99
|
------------------
|
|
95
100
|
|
|
96
|
-
*
|
|
101
|
+
* add login && add asset position
|
|
102
|
+
|
|
103
|
+
0.1.3 (2024-04-19)
|
|
104
|
+
------------------
|
|
105
|
+
|
|
106
|
+
* update docs theme
|
|
107
|
+
|
|
108
|
+
0.1.5 (2024-04-24)
|
|
109
|
+
------------------
|
|
110
|
+
|
|
111
|
+
* update login refrence
|
|
97
112
|
|
|
98
113
|
|
|
@@ -41,15 +41,15 @@ Overview
|
|
|
41
41
|
:alt: Supported implementations
|
|
42
42
|
:target: https://pypi.org/project/emtl
|
|
43
43
|
|
|
44
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/riiy/emtl/v0.1.
|
|
44
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/riiy/emtl/v0.1.5.svg
|
|
45
45
|
:alt: Commits since latest release
|
|
46
|
-
:target: https://github.com/riiy/emtl/compare/v0.1.
|
|
46
|
+
:target: https://github.com/riiy/emtl/compare/v0.1.5...master
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
.. end-badges
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
东方财富自动交易系统
|
|
53
53
|
|
|
54
54
|
* Free software: MIT license
|
|
55
55
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
needs_sphinx = "7.2"
|
|
2
|
+
sphinx = "7.2"
|
|
1
3
|
extensions = [
|
|
2
4
|
"sphinx.ext.autodoc",
|
|
3
5
|
"sphinx.ext.autosummary",
|
|
@@ -23,7 +25,7 @@ except Exception:
|
|
|
23
25
|
import traceback
|
|
24
26
|
|
|
25
27
|
traceback.print_exc()
|
|
26
|
-
version = release = "0.1.
|
|
28
|
+
version = release = "0.1.5"
|
|
27
29
|
|
|
28
30
|
pygments_style = "trac"
|
|
29
31
|
templates_path = ["."]
|
|
@@ -32,7 +34,7 @@ extlinks = {
|
|
|
32
34
|
"pr": ("https://github.com/riiy/emtl/pull/%s", "PR #%s"),
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
html_theme = "
|
|
37
|
+
html_theme = "alabaster"
|
|
36
38
|
html_theme_options = {
|
|
37
39
|
"githuburl": "https://github.com/riiy/emtl/",
|
|
38
40
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sphinx==7.2.6
|
|
@@ -16,15 +16,15 @@ setup(
|
|
|
16
16
|
use_scm_version={
|
|
17
17
|
"local_scheme": "dirty-tag",
|
|
18
18
|
"write_to": "src/emtl/_version.py",
|
|
19
|
-
"fallback_version": "0.1.
|
|
19
|
+
"fallback_version": "0.1.5",
|
|
20
20
|
},
|
|
21
21
|
license="MIT",
|
|
22
|
-
description="
|
|
22
|
+
description="东方财富自动交易系统",
|
|
23
23
|
long_description="{}\n{}".format(
|
|
24
24
|
re.compile("^.. start-badges.*^.. end-badges", re.M | re.S).sub("", read("README.rst")),
|
|
25
25
|
re.sub(":[a-z]+:`~?(.*?)`", r"``\1``", read("CHANGELOG.rst")),
|
|
26
26
|
),
|
|
27
|
-
author="
|
|
27
|
+
author="Riiy",
|
|
28
28
|
author_email="riiyzhou@gmail.com",
|
|
29
29
|
url="https://github.com/riiy/emtl",
|
|
30
30
|
packages=find_packages("src"),
|
|
@@ -34,7 +34,7 @@ setup(
|
|
|
34
34
|
zip_safe=False,
|
|
35
35
|
classifiers=[
|
|
36
36
|
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
37
|
-
"Development Status ::
|
|
37
|
+
"Development Status :: 5 - Production/Stable",
|
|
38
38
|
"Intended Audience :: Developers",
|
|
39
39
|
"License :: OSI Approved :: MIT License",
|
|
40
40
|
"Operating System :: Unix",
|
|
@@ -47,7 +47,7 @@ setup(
|
|
|
47
47
|
# "Programming Language :: Python :: 3.9",
|
|
48
48
|
"Programming Language :: Python :: 3.10",
|
|
49
49
|
"Programming Language :: Python :: 3.11",
|
|
50
|
-
"Programming Language :: Python :: 3.12",
|
|
50
|
+
# "Programming Language :: Python :: 3.12",
|
|
51
51
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
52
52
|
# "Programming Language :: Python :: Implementation :: PyPy",
|
|
53
53
|
# uncomment if you test on these interpreters:
|
|
@@ -62,15 +62,15 @@ setup(
|
|
|
62
62
|
"Issue Tracker": "https://github.com/riiy/emtl/issues",
|
|
63
63
|
},
|
|
64
64
|
keywords=[
|
|
65
|
+
"autotrade",
|
|
65
66
|
"trade",
|
|
66
67
|
"东方财富",
|
|
67
68
|
"股票",
|
|
68
69
|
"交易",
|
|
70
|
+
"交易机器人",
|
|
69
71
|
],
|
|
70
|
-
python_requires=">=3.
|
|
71
|
-
install_requires=[
|
|
72
|
-
# eg: "aspectlib==1.1.1", "six>=1.7",
|
|
73
|
-
],
|
|
72
|
+
python_requires=">=3.10",
|
|
73
|
+
install_requires=["rsa==4.9", "requests==2.31.0", "ddddocr==1.4.11", "cryptography==42.0.5"],
|
|
74
74
|
extras_require={
|
|
75
75
|
# eg:
|
|
76
76
|
# "rst": ["docutils>=0.11"],
|
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '0.1.
|
|
16
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
15
|
+
__version__ = version = '0.1.5'
|
|
16
|
+
__version_tuple__ = version_tuple = (0, 1, 5)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
_urls: dict = {
|
|
2
|
+
"yzm": "https://jywg.18.cn/Login/YZM?randNum=",
|
|
3
|
+
"login": "https://jywg.18.cn/Login/Authentication?validatekey=",
|
|
4
|
+
"query_asset_and_pos": "https://jywg.18.cn/Com/queryAssetAndPositionV1?validatekey=",
|
|
5
|
+
"query_orders": "https://jywg.18.cn/Search/GetOrdersData?validatekey=",
|
|
6
|
+
"query_trades": "https://jywg.18.cn/Search/GetDealData?validatekey=",
|
|
7
|
+
"query_his_orders": "https://jywg.18.cn/Search/GetHisOrdersData?validatekey=",
|
|
8
|
+
"query_his_trades": "https://jywg.18.cn/Search/GetHisDealData?validatekey=",
|
|
9
|
+
"query_funds_flow": "https://jywg.18.cn/Search/GetFundsFlow?validatekey=",
|
|
10
|
+
"query_positions": "https://jywg.18.cn/Search/GetStockList?validatekey=",
|
|
11
|
+
"insert_order": "https://jywg.18.cn/Trade/SubmitTradeV2?validatekey=",
|
|
12
|
+
"cancel_order": "https://jywg.18.cn/Trade/RevokeOrders?validatekey=",
|
|
13
|
+
}
|
|
14
|
+
_base_headers: dict = {
|
|
15
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
16
|
+
"Chrome/114.0.0.0 Safari/537.36",
|
|
17
|
+
"Origin": "https://jywg.18.cn",
|
|
18
|
+
"Host": "jywg.18.cn",
|
|
19
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from random import SystemRandom
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ddddocr import DdddOcr
|
|
7
|
+
from requests import Response
|
|
8
|
+
from requests import Session
|
|
9
|
+
from requests import get
|
|
10
|
+
|
|
11
|
+
from .const import _base_headers
|
|
12
|
+
from .const import _urls
|
|
13
|
+
from .utils import Response as Resp
|
|
14
|
+
from .utils import emt_trade_encrypt
|
|
15
|
+
from .utils import get_logger
|
|
16
|
+
from .utils import response_deserialize
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
ocr = DdddOcr(show_ad=False)
|
|
20
|
+
session = Session()
|
|
21
|
+
_em_validate_key = ""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def emt(user, password):
|
|
25
|
+
return user, password
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _check_resp(resp: Response):
|
|
29
|
+
if resp.status_code != 200:
|
|
30
|
+
logger.error(f"request {resp.url} fail, code={resp.status_code}, response={resp.text}")
|
|
31
|
+
return False
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _query_something(tag: str, count: int = 100, data: Optional[dict] = None) -> Optional[Response]:
|
|
36
|
+
"""通用查询函数
|
|
37
|
+
|
|
38
|
+
:param tag: 请求类型
|
|
39
|
+
:param count: 查询数量,可选
|
|
40
|
+
:param data: 请求提交数据,可选
|
|
41
|
+
:return:
|
|
42
|
+
"""
|
|
43
|
+
assert _em_validate_key, "em_validatekey is empty"
|
|
44
|
+
assert tag in _urls, f"{tag} not in url list"
|
|
45
|
+
url = _urls[tag] + _em_validate_key
|
|
46
|
+
if data is None:
|
|
47
|
+
if count <= 0:
|
|
48
|
+
count = 100
|
|
49
|
+
elif count > 1000:
|
|
50
|
+
count = 1000
|
|
51
|
+
data = {
|
|
52
|
+
"qqhs": count,
|
|
53
|
+
"dwc": "",
|
|
54
|
+
}
|
|
55
|
+
headers = _base_headers.copy()
|
|
56
|
+
headers["X-Requested-With"] = "XMLHttpRequest"
|
|
57
|
+
logger.debug(f"(tag={tag}), (data={data}), (url={url})")
|
|
58
|
+
resp = session.post(url, headers=headers, data=data)
|
|
59
|
+
if not _check_resp(resp):
|
|
60
|
+
return None
|
|
61
|
+
logger.debug(resp.text)
|
|
62
|
+
return resp
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _get_captcha_code() -> Optional[tuple[float, Any]]:
|
|
66
|
+
"""get random number and captcha code."""
|
|
67
|
+
cryptogen = SystemRandom()
|
|
68
|
+
random_num = cryptogen.random()
|
|
69
|
+
resp = get(f"{_urls['yzm']}{random_num}", headers=_base_headers, timeout=60)
|
|
70
|
+
if not _check_resp(resp):
|
|
71
|
+
return None
|
|
72
|
+
code = ocr.classification(resp.content)
|
|
73
|
+
logger.debug(f"random_num={random_num}, code={code}")
|
|
74
|
+
if code:
|
|
75
|
+
try:
|
|
76
|
+
return random_num, int(code)
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logger.error(f"get_captcha_code found exception: {e}, ocr result={code}")
|
|
79
|
+
return _get_captcha_code()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _get_em_validate_key():
|
|
83
|
+
"""获取 em_validatekey"""
|
|
84
|
+
url = "https://jywg.18.cn/Trade/Buy"
|
|
85
|
+
resp = session.get(url, headers=_base_headers)
|
|
86
|
+
if not _check_resp(resp):
|
|
87
|
+
return None
|
|
88
|
+
match_result = re.findall(r'id="em_validatekey" type="hidden" value="(.*?)"', resp.text)
|
|
89
|
+
if match_result:
|
|
90
|
+
_em_validatekey = match_result[0].strip()
|
|
91
|
+
global _em_validate_key
|
|
92
|
+
_em_validate_key = _em_validatekey
|
|
93
|
+
return _em_validatekey
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def login(username: str, password: str, duration: int = 30) -> Optional[str]:
|
|
97
|
+
"""登录接口.
|
|
98
|
+
|
|
99
|
+
:param str username: 用户名
|
|
100
|
+
:param str password: 密码(明文)
|
|
101
|
+
:param duration: 在线时长(分钟), defaults to 30
|
|
102
|
+
:type duration: int, optional
|
|
103
|
+
:return:
|
|
104
|
+
"""
|
|
105
|
+
if (ret := _get_captcha_code()) is None:
|
|
106
|
+
return ""
|
|
107
|
+
random_num, code = ret
|
|
108
|
+
logger.error(code)
|
|
109
|
+
headers = _base_headers.copy()
|
|
110
|
+
headers["X-Requested-With"] = "XMLHttpRequest"
|
|
111
|
+
headers["Referer"] = "https://jywg.18.cn/Login?el=1&clear=&returl=%2fTrade%2fBuy"
|
|
112
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
113
|
+
url = _urls["login"]
|
|
114
|
+
data = {
|
|
115
|
+
"userId": username.strip(),
|
|
116
|
+
"password": emt_trade_encrypt(password.strip()),
|
|
117
|
+
"randNumber": random_num,
|
|
118
|
+
"identifyCode": code,
|
|
119
|
+
"duration": duration,
|
|
120
|
+
"authCode": "",
|
|
121
|
+
"type": "Z",
|
|
122
|
+
"secInfo": "",
|
|
123
|
+
}
|
|
124
|
+
resp = session.post(url, headers=headers, data=data)
|
|
125
|
+
if not _check_resp(resp):
|
|
126
|
+
return None
|
|
127
|
+
data = resp.json()
|
|
128
|
+
try:
|
|
129
|
+
resp = response_deserialize(data)
|
|
130
|
+
if resp and resp.status == 0 and resp.message.strip() == "":
|
|
131
|
+
logger.info(f"login success for {resp.data[0]['khmc']}({username})")
|
|
132
|
+
return _get_em_validate_key()
|
|
133
|
+
except KeyError as e:
|
|
134
|
+
logger.error(f"param data found exception:[{e}], [data={data}]")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def query_asset_and_position() -> Optional[Resp]:
|
|
138
|
+
"""Get asset and position."""
|
|
139
|
+
resp = _query_something("query_asset_and_pos")
|
|
140
|
+
if resp:
|
|
141
|
+
return response_deserialize(resp.json())
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from .. import emt
|
|
5
|
+
from .. import login
|
|
6
|
+
from .. import query_asset_and_position
|
|
7
|
+
from ..utils import Response
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_emt():
|
|
11
|
+
assert emt("user", "pass") == ("user", "pass")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_emt_empty():
|
|
15
|
+
assert emt("", "") == ("", "")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_login():
|
|
19
|
+
validate_key = login(os.getenv("EM_USERNAME", ""), os.getenv("EM_PASSWORD", ""))
|
|
20
|
+
if validate_key:
|
|
21
|
+
assert len(validate_key) == len("b91d8012-b70b-4265-bb5d-f79442531017")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_query_asset_position():
|
|
25
|
+
resp: Optional[Response] = query_asset_and_position()
|
|
26
|
+
if resp:
|
|
27
|
+
assert resp.error_code == 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from cryptography.hazmat.primitives import serialization
|
|
8
|
+
from cryptography.hazmat.primitives.asymmetric import padding
|
|
9
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
10
|
+
|
|
11
|
+
rsa_public_key = """
|
|
12
|
+
-----BEGIN PUBLIC KEY-----
|
|
13
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHdsyxT66pDG4p73yope7jxA92
|
|
14
|
+
c0AT4qIJ/xtbBcHkFPK77upnsfDTJiVEuQDH+MiMeb+XhCLNKZGp0yaUU6GlxZdp
|
|
15
|
+
+nLW8b7Kmijr3iepaDhcbVTsYBWchaWUXauj9Lrhz58/6AE/NF0aMolxIGpsi+ST
|
|
16
|
+
2hSHPu3GSXMdhPCkWQIDAQAB
|
|
17
|
+
-----END PUBLIC KEY-----
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Response:
|
|
23
|
+
message: str
|
|
24
|
+
status: int
|
|
25
|
+
error_code: str
|
|
26
|
+
data: Any
|
|
27
|
+
|
|
28
|
+
def is_ok(self) -> bool:
|
|
29
|
+
return not self.message and self.status == 0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_logger(name):
|
|
33
|
+
"""Logger."""
|
|
34
|
+
formater = "%(asctime)s %(name)-20s %(funcName)s %(lineno)d: %(levelname)-8s: %(message)s"
|
|
35
|
+
logging.basicConfig(format=formater, force=True, level=logging.INFO)
|
|
36
|
+
logger = logging.getLogger(name)
|
|
37
|
+
return logger
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def response_deserialize(data: dict) -> Optional[Response]:
|
|
41
|
+
if data is None:
|
|
42
|
+
return None
|
|
43
|
+
return Response(
|
|
44
|
+
data["Message"] if "Message" in data else "", data["Status"], data["Errcode"] if "Errcode" in data else "", data["Data"]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def emt_trade_encrypt(content: str) -> str:
|
|
49
|
+
_pub_key: rsa.RSAPublicKey = serialization.load_pem_public_key(rsa_public_key.encode("utf-8")) # type:ignore
|
|
50
|
+
encrypt_text = _pub_key.encrypt(content.encode(), padding.PKCS1v15())
|
|
51
|
+
return base64.b64encode(encrypt_text).decode("utf-8")
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: emtl
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: 东方财富自动交易系统
|
|
5
5
|
Home-page: https://github.com/riiy/emtl
|
|
6
|
-
Author:
|
|
6
|
+
Author: Riiy
|
|
7
7
|
Author-email: riiyzhou@gmail.com
|
|
8
8
|
License: MIT
|
|
9
9
|
Project-URL: Documentation, https://emtl.readthedocs.io/
|
|
10
10
|
Project-URL: Changelog, https://emtl.readthedocs.io/en/latest/changelog.html
|
|
11
11
|
Project-URL: Issue Tracker, https://github.com/riiy/emtl/issues
|
|
12
|
-
Keywords: trade
|
|
12
|
+
Keywords: autotrade,trade,东方财富,股票,交易,交易机器人
|
|
13
13
|
Platform: UNKNOWN
|
|
14
|
-
Classifier: Development Status ::
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
17
|
Classifier: Operating System :: Unix
|
|
@@ -21,10 +21,9 @@ Classifier: Programming Language :: Python :: 3
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
25
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
25
|
Classifier: Topic :: Utilities
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
28
27
|
License-File: LICENSE
|
|
29
28
|
License-File: AUTHORS.rst
|
|
30
29
|
|
|
@@ -34,7 +33,7 @@ Overview
|
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
东方财富自动交易系统
|
|
38
37
|
|
|
39
38
|
* Free software: MIT license
|
|
40
39
|
|
|
@@ -85,14 +84,30 @@ Note, to combine the coverage data from all the tox environments run:
|
|
|
85
84
|
Changelog
|
|
86
85
|
=========
|
|
87
86
|
|
|
87
|
+
|
|
88
|
+
0.1.0 (2024-04-14)
|
|
89
|
+
------------------
|
|
90
|
+
|
|
91
|
+
* First release on PyPI.
|
|
92
|
+
|
|
88
93
|
0.1.1 (2024-04-16)
|
|
89
94
|
------------------
|
|
90
95
|
|
|
91
96
|
* Delete python3.8 python3.9 pypy.
|
|
92
97
|
|
|
93
|
-
0.1.
|
|
98
|
+
0.1.2 (2024-04-18)
|
|
94
99
|
------------------
|
|
95
100
|
|
|
96
|
-
*
|
|
101
|
+
* add login && add asset position
|
|
102
|
+
|
|
103
|
+
0.1.3 (2024-04-19)
|
|
104
|
+
------------------
|
|
105
|
+
|
|
106
|
+
* update docs theme
|
|
107
|
+
|
|
108
|
+
0.1.5 (2024-04-24)
|
|
109
|
+
------------------
|
|
110
|
+
|
|
111
|
+
* update login refrence
|
|
97
112
|
|
|
98
113
|
|
|
@@ -14,6 +14,7 @@ pyproject.toml
|
|
|
14
14
|
pytest.ini
|
|
15
15
|
setup.py
|
|
16
16
|
tox.ini
|
|
17
|
+
.github/workflows/document.yml
|
|
17
18
|
.github/workflows/github-actions.yml
|
|
18
19
|
ci/bootstrap.py
|
|
19
20
|
ci/requirements.txt
|
|
@@ -34,12 +35,15 @@ src/emtl/__init__.py
|
|
|
34
35
|
src/emtl/__main__.py
|
|
35
36
|
src/emtl/_version.py
|
|
36
37
|
src/emtl/cli.py
|
|
38
|
+
src/emtl/const.py
|
|
37
39
|
src/emtl/core.py
|
|
40
|
+
src/emtl/utils.py
|
|
38
41
|
src/emtl.egg-info/PKG-INFO
|
|
39
42
|
src/emtl.egg-info/SOURCES.txt
|
|
40
43
|
src/emtl.egg-info/dependency_links.txt
|
|
41
44
|
src/emtl.egg-info/entry_points.txt
|
|
42
45
|
src/emtl.egg-info/not-zip-safe
|
|
46
|
+
src/emtl.egg-info/requires.txt
|
|
43
47
|
src/emtl.egg-info/top_level.txt
|
|
44
48
|
src/emtl/tests/__init__.py
|
|
45
49
|
src/emtl/tests/test_cli.py
|
|
@@ -14,7 +14,7 @@ envlist =
|
|
|
14
14
|
clean,
|
|
15
15
|
check,
|
|
16
16
|
docs,
|
|
17
|
-
{py310,py311
|
|
17
|
+
{py310,py311}-{cover,nocov},
|
|
18
18
|
report
|
|
19
19
|
ignore_basepython_conflict = true
|
|
20
20
|
|
|
@@ -22,7 +22,6 @@ ignore_basepython_conflict = true
|
|
|
22
22
|
basepython =
|
|
23
23
|
py310: {env:TOXPYTHON:python3.10}
|
|
24
24
|
py311: {env:TOXPYTHON:python3.11}
|
|
25
|
-
py312: {env:TOXPYTHON:python3.12}
|
|
26
25
|
{bootstrap,clean,check,report,docs,codecov}: {env:TOXPYTHON:python3}
|
|
27
26
|
setenv =
|
|
28
27
|
PYTHONPATH={toxinidir}/tests
|
emtl-0.1.2.dev2/CHANGELOG.rst
DELETED
emtl-0.1.2.dev2/src/emtl/core.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|