-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4fc8921
commit 479e473
Showing
10 changed files
with
364 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[flake8] | ||
exclude = build,__pycache__,__init__.py | ||
ignore = | ||
E501 line too long, fixed by black | ||
W503 line break before binary operator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,33 @@ | ||
# vnpy_excelrtd | ||
vn.py框架的Excel RTD应用模块 | ||
|
||
<p align="center"> | ||
<img src ="https://vnpy.oss-cn-shanghai.aliyuncs.com/vnpy-logo.png"/> | ||
</p> | ||
|
||
<p align="center"> | ||
<img src ="https://img.shields.io/badge/version-1.0.0-blueviolet.svg"/> | ||
<img src ="https://img.shields.io/badge/platform-windows|linux|macos-yellow.svg"/> | ||
<img src ="https://img.shields.io/badge/python-3.7-blue.svg" /> | ||
<img src ="https://img.shields.io/github/license/vnpy/vnpy.svg?color=orange"/> | ||
</p> | ||
|
||
## 说明 | ||
|
||
RTD全称是RealTimeData,是微软提供的主要面向金融行业中实时数据需求设计的Excel数据对接方案,而ExcelRtd模块则是vn.py官方提供的用于实现在Excel中访问vn.py程序内任意数据信息的功能模块。 | ||
|
||
## 安装 | ||
|
||
安装需要基于2.7.0版本以上的[VN Studio](https://www.vnpy.com)。 | ||
|
||
直接使用pip命令: | ||
|
||
``` | ||
pip install vnpy_excelrtd | ||
``` | ||
|
||
下载解压后在cmd中运行 | ||
|
||
``` | ||
python setup.py install | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[metadata] | ||
name = vnpy_excelrtd | ||
version = 1.0.0 | ||
url = https://www.vnpy.com | ||
license = MIT | ||
author = Xiaoyou Chen | ||
author_email = [email protected] | ||
description = excel RTD application for vn.py quant trading framework. | ||
long_description = file: README.md | ||
long_description_content_type = text/markdown | ||
keywords = | ||
quant | ||
quantitative | ||
investment | ||
trading | ||
algotrading | ||
classifiers = | ||
Development Status :: 5 - Production/Stable | ||
Operating System :: OS Independent | ||
Programming Language :: Python :: 3 | ||
Programming Language :: Python :: 3.7 | ||
Programming Language :: Python :: 3.8 | ||
Programming Language :: Python :: 3.9 | ||
Programming Language :: Python :: 3.10 | ||
Topic :: Office/Business :: Financial :: Investment | ||
Programming Language :: Python :: Implementation :: CPython | ||
License :: OSI Approved :: MIT License | ||
Natural Language :: Chinese (Simplified) | ||
|
||
[options] | ||
packages = find: | ||
zip_safe = False | ||
install_requires = | ||
importlib_metadata | ||
|
||
[options.package_data] | ||
* = *.ico |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from setuptools import setup | ||
|
||
setup() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from pathlib import Path | ||
from vnpy.trader.app import BaseApp | ||
from .engine import RtdEngine, APP_NAME | ||
|
||
|
||
class ExcelRtdApp(BaseApp): | ||
"""""" | ||
app_name = APP_NAME | ||
app_module = __module__ | ||
app_path = Path(__file__).parent | ||
display_name = "Excel RTD" | ||
engine_class = RtdEngine | ||
widget_name = "RtdManager" | ||
icon_name = "rtd.ico" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
"""""" | ||
|
||
from typing import Set | ||
|
||
from vnpy.event import Event, EventEngine | ||
from vnpy.rpc import RpcServer | ||
from vnpy.trader.engine import BaseEngine, MainEngine | ||
from vnpy.trader.object import TickData, LogData, SubscribeRequest | ||
from vnpy.trader.event import EVENT_TICK | ||
|
||
|
||
APP_NAME = "ExcelRtd" | ||
|
||
EVENT_RTD_LOG = "eRtdLog" | ||
|
||
REP_ADDRESS = "tcp://*:9001" | ||
PUB_ADDRESS = "tcp://*:9002" | ||
|
||
|
||
class RtdEngine(BaseEngine): | ||
""" | ||
The engine for managing RTD objects and data update. | ||
""" | ||
|
||
def __init__(self, main_engine: MainEngine, event_engine: EventEngine): | ||
"""""" | ||
super().__init__(main_engine, event_engine, APP_NAME) | ||
|
||
self.server: RpcServer = RpcServer() | ||
self.server.register(self.subscribe) | ||
self.server.register(self.write_log) | ||
self.server.start(REP_ADDRESS, PUB_ADDRESS) | ||
|
||
self.subscribed: Set[str] = set() | ||
|
||
self.register_event() | ||
|
||
def register_event(self) -> None: | ||
""" | ||
Register event handler. | ||
""" | ||
self.event_engine.register(EVENT_TICK, self.process_tick_event) | ||
|
||
def process_tick_event(self, event: Event) -> None: | ||
""" | ||
Process tick event and update related RTD value. | ||
""" | ||
tick: TickData = event.data | ||
self.server.publish("tick", tick) | ||
|
||
def write_log(self, msg: str) -> None: | ||
""" | ||
Output RTD related log message. | ||
""" | ||
log = LogData(msg=msg, gateway_name=APP_NAME) | ||
event = Event(EVENT_RTD_LOG, log) | ||
self.event_engine.put(event) | ||
|
||
def subscribe(self, vt_symbol: str) -> None: | ||
""" | ||
Subscribe tick data update. | ||
""" | ||
contract = self.main_engine.get_contract(vt_symbol) | ||
if not contract: | ||
return | ||
|
||
if vt_symbol in self.subscribed: | ||
return | ||
self.subscribed.add(vt_symbol) | ||
|
||
req = SubscribeRequest( | ||
contract.symbol, | ||
contract.exchange | ||
) | ||
self.main_engine.subscribe(req, contract.gateway_name) | ||
|
||
def close(self): | ||
"""""" | ||
self.server.stop() | ||
self.server.join() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .widget import RtdManager |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from pathlib import Path | ||
|
||
from vnpy.event import EventEngine, Event | ||
from vnpy.trader.engine import MainEngine | ||
from vnpy.trader.ui import QtWidgets, QtCore | ||
from vnpy.trader.object import LogData | ||
from ..engine import APP_NAME, EVENT_RTD_LOG | ||
|
||
|
||
class RtdManager(QtWidgets.QWidget): | ||
"""""" | ||
signal_log = QtCore.pyqtSignal(Event) | ||
|
||
def __init__(self, main_engine: MainEngine, event_engine: EventEngine): | ||
"""""" | ||
super().__init__() | ||
|
||
self.main_engine = main_engine | ||
self.event_engine = event_engine | ||
self.rm_engine = main_engine.get_engine(APP_NAME) | ||
|
||
self.init_ui() | ||
self.register_event() | ||
|
||
def init_ui(self) -> None: | ||
""" | ||
Init widget ui components. | ||
""" | ||
self.setWindowTitle("Excel RTD") | ||
self.resize(600, 600) | ||
|
||
module_path = Path(__file__).parent.parent | ||
client_path = module_path.joinpath("vnpy_rtd.py") | ||
self.client_line = QtWidgets.QLineEdit(str(client_path)) | ||
self.client_line.setReadOnly(True) | ||
|
||
copy_button = QtWidgets.QPushButton("复制") | ||
copy_button.clicked.connect(self.copy_client_path) | ||
|
||
self.log_monitor = QtWidgets.QTextEdit() | ||
self.log_monitor.setReadOnly(True) | ||
|
||
self.port_label = QtWidgets.QLabel( | ||
"使用Socket端口:请求回应9001、广播推送9002" | ||
) | ||
|
||
hbox = QtWidgets.QHBoxLayout() | ||
hbox.addWidget(self.client_line) | ||
hbox.addWidget(copy_button) | ||
|
||
vbox = QtWidgets.QVBoxLayout() | ||
vbox.addLayout(hbox) | ||
vbox.addWidget(self.log_monitor) | ||
vbox.addWidget(self.port_label) | ||
self.setLayout(vbox) | ||
|
||
def register_event(self) -> None: | ||
""" | ||
Register event handler. | ||
""" | ||
self.signal_log.connect(self.process_log_event) | ||
|
||
self.event_engine.register(EVENT_RTD_LOG, self.signal_log.emit) | ||
|
||
def process_log_event(self, event: Event) -> None: | ||
""" | ||
Show log message in monitor. | ||
""" | ||
log: LogData = event.data | ||
|
||
msg = f"{log.time}: {log.msg}" | ||
self.log_monitor.append(msg) | ||
|
||
def copy_client_path(self) -> None: | ||
""" | ||
Copy path of client python file to clipboard. | ||
""" | ||
self.client_line.selectAll() | ||
self.client_line.copy() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
"""""" | ||
|
||
from typing import Dict, Set, Any | ||
from collections import defaultdict | ||
|
||
from pyxll import RTD, xl_func | ||
|
||
from vnpy.rpc import RpcClient | ||
from vnpy.trader.object import TickData | ||
|
||
|
||
REQ_ADDRESS = "tcp://localhost:9001" | ||
SUB_ADDRESS = "tcp://localhost:9002" | ||
|
||
|
||
rtd_client: "RtdClient" = None | ||
|
||
|
||
class ObjectRtd(RTD): | ||
""" | ||
RTD proxy for object in Python. | ||
""" | ||
|
||
def __init__(self, engine: "RtdClient", name: str, field: str): | ||
"""Constructor""" | ||
super().__init__(value=0) | ||
|
||
self.engine = engine | ||
self.name = name | ||
self.field = field | ||
|
||
def connect(self) -> None: | ||
""" | ||
Callback when excel cell rtd is connected. | ||
""" | ||
self.engine.add_rtd(self) | ||
|
||
def disconnect(self) -> None: | ||
""" | ||
Callback when excel cell rtd is disconncted. | ||
""" | ||
self.engine.remove_rtd(self) | ||
|
||
def update(self, data: Any) -> None: | ||
""" | ||
Update value in excel cell. | ||
""" | ||
new_value = getattr(data, self.field, "N/A") | ||
|
||
if new_value != self.value: | ||
self.value = new_value | ||
|
||
|
||
class RtdClient(RpcClient): | ||
""" | ||
The engine for managing RTD objects and data update. | ||
""" | ||
|
||
def __init__(self): | ||
"""""" | ||
super().__init__() | ||
|
||
self.rtds: Dict[str, Set[ObjectRtd]] = defaultdict(set) | ||
|
||
global rtd_client | ||
rtd_client = self | ||
|
||
def callback(self, topic: str, data: Any) -> None: | ||
"""""" | ||
tick: TickData = data | ||
buf = self.rtds[tick.vt_symbol] | ||
|
||
for rtd in buf: | ||
rtd.update(tick) | ||
|
||
def add_rtd(self, rtd: ObjectRtd) -> None: | ||
""" | ||
Add a new RTD into the engine.. | ||
""" | ||
buf = self.rtds[rtd.name] | ||
buf.add(rtd) | ||
self.write_log(f"新增RTD连接:{rtd.name} {rtd.field}") | ||
|
||
# Auto subscribe tick data | ||
self.subscribe(rtd.name) | ||
|
||
def remove_rtd(self, rtd: ObjectRtd) -> None: | ||
""" | ||
Remove an existing RTD from the engine. | ||
""" | ||
buf = self.rtds[self.name] | ||
if self in buf: | ||
buf.remove(rtd) | ||
self.write_log(f"移除RTD连接:{rtd.name} {rtd.field}") | ||
|
||
|
||
def init_client() -> None: | ||
"""Initialize vnpy rtd client""" | ||
global rtd_client | ||
rtd_client = RtdClient() | ||
rtd_client.subscribe_topic("") | ||
rtd_client.start(REQ_ADDRESS, SUB_ADDRESS) | ||
|
||
|
||
@xl_func("string vt_symbol, string field: rtd") | ||
def rtd_tick_data(vt_symbol: str, field: str) -> ObjectRtd: | ||
""" | ||
Return the streaming value of the tick data field. | ||
""" | ||
if not rtd_client: | ||
init_client() | ||
|
||
rtd = ObjectRtd(rtd_client, vt_symbol, field) | ||
return rtd |