vnpy-componentmgr 1.0.0__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.
Files changed (25) hide show
  1. vnpy_componentmgr-1.0.0/.gitignore +43 -0
  2. vnpy_componentmgr-1.0.0/PKG-INFO +55 -0
  3. vnpy_componentmgr-1.0.0/README.md +31 -0
  4. vnpy_componentmgr-1.0.0/pyproject.toml +59 -0
  5. vnpy_componentmgr-1.0.0/scripts/run.py +9 -0
  6. vnpy_componentmgr-1.0.0/setup.cfg +4 -0
  7. vnpy_componentmgr-1.0.0/setup.py +19 -0
  8. vnpy_componentmgr-1.0.0/vnpy_componentmgr/__init__.py +13 -0
  9. vnpy_componentmgr-1.0.0/vnpy_componentmgr/componentmgr.py +179 -0
  10. vnpy_componentmgr-1.0.0/vnpy_componentmgr/constants.py +17 -0
  11. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/__init__.py +11 -0
  12. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/build_hook.py +23 -0
  13. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/en/LC_MESSAGES/vnpy.po +657 -0
  14. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/generate_mo.bat +1 -0
  15. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/generate_pot.bat +1 -0
  16. vnpy_componentmgr-1.0.0/vnpy_componentmgr/locale/vnpy.pot +629 -0
  17. vnpy_componentmgr-1.0.0/vnpy_componentmgr/start_ui.py +17 -0
  18. vnpy_componentmgr-1.0.0/vnpy_componentmgr/utility.py +114 -0
  19. vnpy_componentmgr-1.0.0/vnpy_componentmgr/widgets.py +78 -0
  20. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/PKG-INFO +55 -0
  21. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/SOURCES.txt +23 -0
  22. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/dependency_links.txt +1 -0
  23. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/entry_points.txt +2 -0
  24. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/requires.txt +7 -0
  25. vnpy_componentmgr-1.0.0/vnpy_componentmgr.egg-info/top_level.txt +1 -0
@@ -0,0 +1,43 @@
1
+ # Python
2
+ *.pyc
3
+ *.pyo
4
+ *.pyd
5
+ *.egg-info/
6
+
7
+ # Jupyter
8
+ .ipynb_checkpoints
9
+
10
+ # IDE
11
+ .vscode
12
+ .idea
13
+ *.wpr
14
+ *.wpu
15
+ .vs
16
+ x64
17
+
18
+ # Temp
19
+ build
20
+ dist
21
+ *.local
22
+
23
+ # VeighNa
24
+ .vntrader
25
+
26
+ # Visual Studio intermediate files
27
+ *.exp
28
+ *.iobj
29
+ *.ipdb
30
+ *.pdb
31
+
32
+ # Documents
33
+ _build
34
+ _static
35
+ _templates
36
+
37
+ # Misc
38
+ .DS_Store
39
+ *.mo
40
+
41
+ *.log
42
+ # Alpha
43
+ lab/
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: vnpy_componentmgr
3
+ Version: 1.0.0
4
+ Summary: Trade panels for traders' convenience.
5
+ Author-email: YQ Cui <qianyun210603@hotmail.com>
6
+ License-Expression: MIT
7
+ Keywords: quant,quantitative,investment,trading,algotrading
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Topic :: Office/Business :: Financial :: Investment
14
+ Classifier: Programming Language :: Python :: Implementation :: CPython
15
+ Classifier: Natural Language :: Chinese (Simplified)
16
+ Requires-Python: >=3.12
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: PySide6
19
+ Provides-Extra: dev
20
+ Requires-Dist: ruff>=0.0.263; extra == "dev"
21
+ Requires-Dist: setuptools_scm>=8; extra == "dev"
22
+ Requires-Dist: setuptools>=64; extra == "dev"
23
+ Requires-Dist: wheel; extra == "dev"
24
+
25
+
26
+ <h1 style="text-align: center;">VeighNa框架的模块管理器</h1>
27
+
28
+ ***
29
+
30
+ <p style="text-align: center;">
31
+ <img src ="https://img.shields.io/badge/version-1.0.0-blueviolet.svg" alt=""/>
32
+ <img src ="https://img.shields.io/badge/platform-windows|linux-yellow.svg" alt=""/>
33
+ <img src ="https://img.shields.io/badge/python-3.11|3.12|3.13-blue.svg" alt=""/>
34
+ <img src ="https://img.shields.io/github/license/vnpy/vnpy.svg?color=orange" alt=""/>
35
+ </p>
36
+
37
+ ## 说明
38
+
39
+ 管理vnpy模块的安装/更新和加载。
40
+
41
+ ## 安装
42
+
43
+ 安装环境推荐基于4.3.0.5版本以上的【[**VeighNa Studio**](https://www.vnpy.com)】。
44
+
45
+ 直接使用pip命令:
46
+
47
+ ```
48
+ pip install vnpy_componentmgr
49
+ ```
50
+
51
+ 或者下载源代码后,解压后在cmd中运行:
52
+
53
+ ```
54
+ pip install .
55
+ ```
@@ -0,0 +1,31 @@
1
+
2
+ <h1 style="text-align: center;">VeighNa框架的模块管理器</h1>
3
+
4
+ ***
5
+
6
+ <p style="text-align: center;">
7
+ <img src ="https://img.shields.io/badge/version-1.0.0-blueviolet.svg" alt=""/>
8
+ <img src ="https://img.shields.io/badge/platform-windows|linux-yellow.svg" alt=""/>
9
+ <img src ="https://img.shields.io/badge/python-3.11|3.12|3.13-blue.svg" alt=""/>
10
+ <img src ="https://img.shields.io/github/license/vnpy/vnpy.svg?color=orange" alt=""/>
11
+ </p>
12
+
13
+ ## 说明
14
+
15
+ 管理vnpy模块的安装/更新和加载。
16
+
17
+ ## 安装
18
+
19
+ 安装环境推荐基于4.3.0.5版本以上的【[**VeighNa Studio**](https://www.vnpy.com)】。
20
+
21
+ 直接使用pip命令:
22
+
23
+ ```
24
+ pip install vnpy_componentmgr
25
+ ```
26
+
27
+ 或者下载源代码后,解压后在cmd中运行:
28
+
29
+ ```
30
+ pip install .
31
+ ```
@@ -0,0 +1,59 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel", "setuptools_scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vnpy_componentmgr"
7
+ dynamic = ["version"]
8
+ license = "MIT"
9
+ authors = [{ name = "YQ Cui", email = "qianyun210603@hotmail.com" }]
10
+ description = "Trade panels for traders' convenience."
11
+ readme = { file = "README.md", content-type = "text/markdown" }
12
+ keywords = ["quant", "quantitative", "investment", "trading", "algotrading"]
13
+ classifiers = [
14
+ "Development Status :: 5 - Production/Stable",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Office/Business :: Financial :: Investment",
20
+ "Programming Language :: Python :: Implementation :: CPython",
21
+ "Natural Language :: Chinese (Simplified)"]
22
+ requires-python = ">=3.12"
23
+
24
+ dependencies = [
25
+ "PySide6",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "ruff>=0.0.263",
31
+ "setuptools_scm>=8",
32
+ "setuptools>=64",
33
+ "wheel",
34
+ ]
35
+
36
+ [project.scripts]
37
+ vnpy_componentmgr = "vnpy_componentmgr.start_ui:run_module_manager"
38
+
39
+ [tool.setuptools]
40
+ include-package-data = true
41
+
42
+ [tool.setuptools_scm]
43
+
44
+ [tool.ruff]
45
+ target-version = "py313"
46
+ output-format = "full"
47
+ line-length = 120
48
+ exclude = ["*.ipynb"]
49
+
50
+ [tool.ruff.lint]
51
+ select = [
52
+ "B", # flake8-bugbear
53
+ "E", # pycodestyle error
54
+ "F", # pyflakes
55
+ "UP", # pyupgrade
56
+ "W", # pycodestyle warning
57
+ "PL" # pylint
58
+ ]
59
+ ignore = ["UP008", "E501", "PLR0913", "I001", "PLR2004", "PLR0915", "B027", "PLR5501", "PLR0912", "PLR0911"]
@@ -0,0 +1,9 @@
1
+ # @Time : 2026/4/7 13:57
2
+ # @Author : YQ Tsui
3
+ # @File : run.py
4
+ # @Purpose :
5
+
6
+ from vnpy_componentmgr.start_ui import run_module_manager
7
+
8
+ if __name__ == "__main__":
9
+ run_module_manager()
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ from setuptools_scm.version import ScmVersion, guess_next_version
2
+ from setuptools import setup
3
+
4
+
5
+ def custom_local_scheme(version: ScmVersion):
6
+ if version.exact:
7
+ return ""
8
+ else:
9
+ return "+git." + version.node[1:8] if version.node else ""
10
+
11
+
12
+ def custom_version_scheme(version: ScmVersion):
13
+ if version.exact:
14
+ return version.format_with("{tag}")
15
+ else:
16
+ return guess_next_version(version)
17
+
18
+
19
+ setup(use_scm_version={"version_scheme": custom_version_scheme, "local_scheme": custom_local_scheme})
@@ -0,0 +1,13 @@
1
+ # @Time : 2026/4/6 14:19
2
+ # @Author : YQ Tsui
3
+ # @File : __init__.py.py
4
+ # @Purpose :
5
+
6
+ import importlib.metadata as importlib_metadata
7
+
8
+ try:
9
+ __version__ = importlib_metadata.version("vnpy_componentmgr")
10
+ except importlib_metadata.PackageNotFoundError:
11
+ __version__ = "dev"
12
+
13
+ __all__ = ["ComponentManagementDialog"]
@@ -0,0 +1,179 @@
1
+ # @Time : 2026/4/6 15:07
2
+ # @Author : YQ Tsui
3
+ # @File : componentmgr.py
4
+ # @Purpose :
5
+
6
+ from functools import partial
7
+ from vnpy.trader.utility import (
8
+ load_json,
9
+ save_json,
10
+ )
11
+ from vnpy.trader.ui import QtWidgets, Qt
12
+ from vnpy.trader.locale import _
13
+
14
+ from . import __version__
15
+ from .constants import AVAILABLE_APP, AVAILABLE_GATEWAY, VNPY_URL
16
+ from .widgets import UpdatingProgressBar
17
+ from .utility import get_local_version, get_remote_version
18
+
19
+
20
+ class ComponentManagementDialog(QtWidgets.QDialog):
21
+ def __init__(self, parent=None) -> None:
22
+ """"""
23
+ super().__init__(parent)
24
+ self.row_mapping = {}
25
+ self.update_progress = None
26
+ self.selected_modules = load_json("vnpy_selectmodules.json")
27
+ self.init_ui()
28
+
29
+ def init_ui(self) -> None:
30
+ """"""
31
+ self.setWindowTitle(_(f"模块管理 - 选择要启用的模块和更新模块 (v{__version__})"))
32
+
33
+ self.select_module_at_start_checkbox = QtWidgets.QCheckBox(_("启动vnpy时选择模块?"))
34
+ self.select_module_at_start_checkbox.setChecked(self.selected_modules.get("select_at_start_up", True))
35
+
36
+ self.modules_grid = QtWidgets.QTableWidget()
37
+ self.modules_grid.setColumnCount(6)
38
+ self.modules_grid.setColumnWidth(0, 100)
39
+ self.modules_grid.setColumnWidth(1, 200)
40
+ self.modules_grid.setColumnWidth(2, 150)
41
+ self.modules_grid.setColumnWidth(3, 150)
42
+ self.modules_grid.setColumnWidth(4, 60)
43
+ self.modules_grid.setColumnWidth(5, 40)
44
+ self.modules_grid.setHorizontalHeaderLabels(
45
+ [_("模块"), _("Python包"), _("本地版本"), _("最新版本"), _("更新"), _("启用")]
46
+ )
47
+ self.modules_grid.setRowCount(0)
48
+ self.modules_grid.verticalHeader().setVisible(False)
49
+ self.modules_grid.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
50
+ self.modules_grid.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
51
+ button_box = QtWidgets.QDialogButtonBox()
52
+ ok_button = button_box.addButton(_("保存并退出"), QtWidgets.QDialogButtonBox.AcceptRole)
53
+ ok_button.clicked.connect(self.accept)
54
+ cancel_button = button_box.addButton(_("取消"), QtWidgets.QDialogButtonBox.RejectRole)
55
+ cancel_button.clicked.connect(self.reject)
56
+ self.modules_grid.setCellWidget(0, 4, button_box)
57
+
58
+ total_height = self.modules_grid.frameWidth() * 2 + self.modules_grid.horizontalHeader().height()
59
+
60
+ self._add_row(_("核心"), "vnpy", VNPY_URL, True)
61
+ total_height += self.modules_grid.rowHeight(0)
62
+
63
+ for appname, giturl in AVAILABLE_APP.items():
64
+ selected = appname in self.selected_modules.get("APPs", [])
65
+ self._add_row(appname, f"vnpy_{appname.lower()}", giturl, selected)
66
+ total_height += self.modules_grid.rowHeight(self.modules_grid.rowCount() - 1)
67
+
68
+ for gwname, giturl in AVAILABLE_GATEWAY.items():
69
+ selected = gwname in self.selected_modules.get("Gateways", [])
70
+ self._add_row(gwname, f"vnpy_{gwname.lower()}", giturl, selected)
71
+ total_height += self.modules_grid.rowHeight(self.modules_grid.rowCount() - 1)
72
+
73
+ self.modules_grid.setFixedSize(720, min(900, total_height + 8))
74
+
75
+ self.vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
76
+ self.vbox.addWidget(self.select_module_at_start_checkbox)
77
+ self.vbox.addWidget(self.modules_grid)
78
+ self.vbox.addWidget(button_box)
79
+
80
+ self.setLayout(self.vbox)
81
+ self.setFixedWidth(self.sizeHint().width())
82
+
83
+ def _add_row(self, app_or_gw_name: str, module_name: str, git_url: str, selected=False, style=None) -> None:
84
+ """
85
+ Add a row to the modules grid.
86
+ """
87
+ row = self.modules_grid.rowCount()
88
+ self.modules_grid.insertRow(row)
89
+ self.row_mapping[app_or_gw_name] = row
90
+ cell_name = QtWidgets.QTableWidgetItem(app_or_gw_name) # app or gateway name
91
+ self.modules_grid.setItem(row, 0, cell_name)
92
+ cell_module_name = QtWidgets.QTableWidgetItem(module_name) # module name
93
+ self.modules_grid.setItem(row, 1, cell_module_name)
94
+ self.row_mapping[module_name] = row
95
+ local_version = get_local_version(module_name)
96
+
97
+ cell_local = QtWidgets.QTableWidgetItem(local_version) # local version
98
+ self.modules_grid.setItem(row, 2, cell_local)
99
+
100
+ remote_version = self._get_remote_version(git_url)
101
+ cell_latest = QtWidgets.QTableWidgetItem(remote_version)
102
+ self.modules_grid.setItem(row, 3, cell_latest)
103
+
104
+ button = QtWidgets.QPushButton(_("安装") if local_version == "--" else _("更新"))
105
+ button.setObjectName(app_or_gw_name)
106
+ button.setEnabled(bool(remote_version) and remote_version not in ("--", local_version))
107
+ button.clicked.connect(partial(self.update_module, row_idx=row, git_url=git_url))
108
+ self.modules_grid.setCellWidget(row, 4, button)
109
+
110
+ cell_selected = QtWidgets.QTableWidgetItem()
111
+ cell_selected.setCheckState(Qt.Checked if selected else Qt.Unchecked)
112
+ if app_or_gw_name == _("核心"):
113
+ cell_selected.setFlags(~Qt.ItemIsUserCheckable & Qt.ItemIsEnabled)
114
+ self.modules_grid.setItem(row, 5, cell_selected)
115
+
116
+ @staticmethod
117
+ def _get_remote_version(url: str) -> str:
118
+ """
119
+ Get the remote version of the module.
120
+ """
121
+ try:
122
+ return get_remote_version(url)
123
+ except Exception:
124
+ return "--"
125
+
126
+ def set_button_status(self, row_num: int) -> None:
127
+ remote_version = self.modules_grid.item(row_num, 2).text()
128
+ local_version = self.modules_grid.item(row_num, 1).text()
129
+ if remote_version and remote_version != local_version and _("更新") not in local_version:
130
+ button = self.modules_grid.cellWidget(row_num, 3)
131
+ button.setEnabled(True)
132
+
133
+ def update_module(self, row_idx: int, git_url: str) -> None:
134
+ related_module_name = self.modules_grid.item(row_idx, 1).text().strip()
135
+ if not related_module_name:
136
+ QtWidgets.QMessageBox.warning(self, _("错误"), _("无法获取模块名称,无法更新"))
137
+ return
138
+ for row in range(self.modules_grid.rowCount()):
139
+ button = self.modules_grid.cellWidget(row, 4)
140
+ button.setEnabled(False)
141
+ self.update_progress = UpdatingProgressBar(related_module_name, git_url, self)
142
+ self.vbox.insertWidget(0, self.update_progress)
143
+ QtWidgets.QApplication.processEvents()
144
+ local_version = self.modules_grid.item(row_idx, 2).text().strip()
145
+ install_or_update = _("安装") if local_version in {"--", ""} else _("更新")
146
+ self.update_progress.label.setText(install_or_update)
147
+ self.update_progress.run_update(partial(self.on_update_completed, text=install_or_update))
148
+
149
+ def on_update_completed(self, progressor: UpdatingProgressBar, text: str) -> None:
150
+ cell = self.modules_grid.item(self.row_mapping[progressor.module_name], 2)
151
+ if progressor.error_flag:
152
+ QtWidgets.QMessageBox.critical(self, _(f"{text}失败"), progressor.error_reason + "\n")
153
+ cell.setText(_(f"{text}失败,联系管理员修复。"))
154
+ else:
155
+ cell.setText(_(f"已{text},重启vnpy生效"))
156
+ for row in range(self.modules_grid.rowCount()):
157
+ self.set_button_status(row)
158
+ self.vbox.removeWidget(progressor)
159
+ self.progressor = None
160
+
161
+ def save_selection(self):
162
+ select_at_start_up = self.select_module_at_start_checkbox.isChecked()
163
+ selected_apps = []
164
+ selected_gateways = []
165
+ for row in range(self.modules_grid.rowCount()):
166
+ module_name = self.modules_grid.item(row, 0).text()
167
+ if self.modules_grid.item(row, 5).checkState() == Qt.Checked:
168
+ if module_name in AVAILABLE_APP:
169
+ selected_apps.append(module_name)
170
+ elif module_name in AVAILABLE_GATEWAY:
171
+ selected_gateways.append(module_name)
172
+ self.selected_modules["select_at_start_up"] = select_at_start_up
173
+ self.selected_modules["APPs"] = selected_apps
174
+ self.selected_modules["Gateways"] = selected_gateways
175
+ save_json("vnpy_selectmodules.json", self.selected_modules)
176
+
177
+ def accept(self, /):
178
+ self.save_selection()
179
+ super().accept()
@@ -0,0 +1,17 @@
1
+ # @Time : 2026/4/6 14:21
2
+ # @Author : YQ Tsui
3
+ # @File : constants.py
4
+ # @Purpose :
5
+
6
+ VNPY_URL = "ssh://git@gitee.com/arb513330/vnpy.git"
7
+
8
+ AVAILABLE_GATEWAY = {
9
+ "Ctp": "ssh://git@gitee.com/arb513330/vnpy_ctp.git",
10
+ "Sopt": "ssh://git@gitee.com/arb513330/vnpy_sopt.git",
11
+ "Xt": "ssh://git@gitee.com/arb513330/vnpy_xt.git",
12
+ "XtRedisOrder": "ssh://git@gitee.com/arb513330/vnpy_xtredisorder.git",
13
+ }
14
+
15
+ AVAILABLE_APP = {
16
+ "TradePanels": "ssh://git@gitee.com/arb513330/vnpy_tradepanels.git",
17
+ }
@@ -0,0 +1,11 @@
1
+ import gettext
2
+ from pathlib import Path
3
+
4
+
5
+ localedir: Path = Path(__file__).parent
6
+
7
+ translations: gettext.GNUTranslations | gettext.NullTranslations = gettext.translation(
8
+ "vnpy", localedir=localedir, fallback=True
9
+ )
10
+
11
+ _ = translations.gettext
@@ -0,0 +1,23 @@
1
+ from pathlib import Path
2
+
3
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
4
+ from babel.messages.mofile import write_mo
5
+ from babel.messages.pofile import read_po
6
+
7
+
8
+ class LocaleBuildHook(BuildHookInterface):
9
+ """Custom build hook for generating .mo files."""
10
+
11
+ def initialize(self, version: str, build_data: dict) -> None:
12
+ """Initialize the build hook"""
13
+ # Only generate mo file when building wheel
14
+ if "pure_python" not in build_data:
15
+ return
16
+
17
+ self.locale_path: Path = Path(self.root).joinpath("vnpy", "trader", "locale")
18
+ self.mo_path: Path = self.locale_path.joinpath("en", "LC_MESSAGES", "vnpy.mo")
19
+ self.po_path: Path = self.locale_path.joinpath("en", "LC_MESSAGES", "vnpy.po")
20
+
21
+ with open(self.mo_path, "wb") as mo_f:
22
+ with open(self.po_path, encoding="utf-8") as po_f:
23
+ write_mo(mo_f, read_po(po_f))