vnpy_scripttrader 1.0.3__py3-none-any.whl

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.
@@ -0,0 +1,47 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2015-present, Xiaoyou Chen
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
+
23
+
24
+ from pathlib import Path
25
+
26
+ import importlib_metadata
27
+ from vnpy.trader.app import BaseApp
28
+
29
+ from .engine import ScriptEngine, APP_NAME
30
+ from .cli import init_cli_trading
31
+
32
+ try:
33
+ __version__ = importlib_metadata.version("vnpy_scripttrader")
34
+ except importlib_metadata.PackageNotFoundError:
35
+ __version__ = "dev"
36
+
37
+
38
+ class ScriptTraderApp(BaseApp):
39
+ """"""
40
+
41
+ app_name: str = APP_NAME
42
+ app_module: str = __module__
43
+ app_path: Path = Path(__file__).parent
44
+ display_name: str = "脚本策略"
45
+ engine_class: ScriptEngine = ScriptEngine
46
+ widget_name: str = "ScriptManager"
47
+ icon_name: str = str(app_path.joinpath("ui", "script.ico"))
@@ -0,0 +1,29 @@
1
+ from typing import Sequence, Type
2
+
3
+ from vnpy.event import EventEngine, Event
4
+ from vnpy.trader.engine import MainEngine
5
+ from vnpy.trader.gateway import BaseGateway
6
+ from vnpy.trader.event import EVENT_LOG
7
+ from vnpy.trader.object import LogData
8
+
9
+ from .engine import ScriptEngine, BaseEngine
10
+
11
+
12
+ def process_log_event(event: Event) -> None:
13
+ """"""
14
+ log: LogData = event.data
15
+ print(f"{log.time}\t{log.msg}")
16
+
17
+
18
+ def init_cli_trading(gateways: Sequence[Type[BaseGateway]]) -> BaseEngine:
19
+ """"""
20
+ event_engine: EventEngine = EventEngine()
21
+ event_engine.register(EVENT_LOG, process_log_event)
22
+
23
+ main_engine: MainEngine = MainEngine(event_engine)
24
+ for gateway in gateways:
25
+ main_engine.add_gateway(gateway)
26
+
27
+ script_engine: ScriptEngine = main_engine.add_engine(ScriptEngine)
28
+
29
+ return script_engine
@@ -0,0 +1,334 @@
1
+ import sys
2
+ import importlib
3
+ import traceback
4
+ from types import ModuleType
5
+ from typing import Optional, Sequence, Any, List
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ from threading import Thread
9
+
10
+ from pandas import DataFrame
11
+
12
+ from vnpy.event import Event, EventEngine
13
+ from vnpy.trader.engine import BaseEngine, MainEngine
14
+ from vnpy.trader.constant import Direction, Offset, OrderType, Interval
15
+ from vnpy.trader.object import (
16
+ BaseData,
17
+ OrderRequest,
18
+ HistoryRequest,
19
+ SubscribeRequest,
20
+ TickData,
21
+ OrderData,
22
+ TradeData,
23
+ PositionData,
24
+ AccountData,
25
+ ContractData,
26
+ LogData,
27
+ BarData,
28
+ CancelRequest
29
+ )
30
+ from vnpy.trader.datafeed import BaseDatafeed, get_datafeed
31
+
32
+
33
+ APP_NAME = "ScriptTrader"
34
+
35
+ EVENT_SCRIPT_LOG = "eScriptLog"
36
+
37
+
38
+ class ScriptEngine(BaseEngine):
39
+ """"""
40
+ setting_filename: str = "script_trader_setting.json"
41
+
42
+ def __init__(self, main_engine: MainEngine, event_engine: EventEngine) -> None:
43
+ """"""
44
+ super().__init__(main_engine, event_engine, APP_NAME)
45
+
46
+ self.strategy_active: bool = False
47
+ self.strategy_thread: Thread = None
48
+
49
+ self.datafeed: BaseDatafeed = get_datafeed()
50
+
51
+ def init(self) -> None:
52
+ """启动策略引擎"""
53
+ result: bool = self.datafeed.init()
54
+ if result:
55
+ self.write_log("数据服务初始化成功")
56
+
57
+ def start_strategy(self, script_path: str) -> None:
58
+ """运行策略线程中的策略方法"""
59
+ if self.strategy_active:
60
+ return
61
+ self.strategy_active: bool = True
62
+
63
+ self.strategy_thread: Thread = Thread(
64
+ target=self.run_strategy, args=(script_path,))
65
+ self.strategy_thread.start()
66
+
67
+ self.write_log("策略交易脚本启动")
68
+
69
+ def run_strategy(self, script_path: str) -> None:
70
+ """加载策略脚本并调用run函数"""
71
+ path: Path = Path(script_path)
72
+ sys.path.append(str(path.parent))
73
+
74
+ script_name: str = path.parts[-1]
75
+ module_name: str = script_name.replace(".py", "")
76
+
77
+ try:
78
+ module: ModuleType = importlib.import_module(module_name)
79
+ importlib.reload(module)
80
+ module.run(self)
81
+ except Exception:
82
+ msg: str = f"触发异常已停止\n{traceback.format_exc()}"
83
+ self.write_log(msg)
84
+
85
+ def stop_strategy(self) -> None:
86
+ """停止运行中的策略"""
87
+ if not self.strategy_active:
88
+ return
89
+ self.strategy_active: bool = False
90
+
91
+ if self.strategy_thread:
92
+ self.strategy_thread.join()
93
+ self.strategy_thread: Thread = None
94
+
95
+ self.write_log("策略交易脚本停止")
96
+
97
+ def connect_gateway(self, setting: dict, gateway_name: str) -> None:
98
+ """"""
99
+ self.main_engine.connect(setting, gateway_name)
100
+
101
+ def send_order(
102
+ self,
103
+ vt_symbol: str,
104
+ price: float,
105
+ volume: float,
106
+ direction: Direction,
107
+ offset: Offset,
108
+ order_type: OrderType
109
+ ) -> str:
110
+ """"""
111
+ contract: Optional[ContractData] = self.get_contract(vt_symbol)
112
+ if not contract:
113
+ return ""
114
+
115
+ req: OrderRequest = OrderRequest(
116
+ symbol=contract.symbol,
117
+ exchange=contract.exchange,
118
+ direction=direction,
119
+ type=order_type,
120
+ volume=volume,
121
+ price=price,
122
+ offset=offset,
123
+ reference=APP_NAME
124
+ )
125
+
126
+ vt_orderid: str = self.main_engine.send_order(req, contract.gateway_name)
127
+ return vt_orderid
128
+
129
+ def subscribe(self, vt_symbols) -> None:
130
+ """"""
131
+ for vt_symbol in vt_symbols:
132
+ contract: Optional[ContractData] = self.main_engine.get_contract(vt_symbol)
133
+ if contract:
134
+ req: SubscribeRequest = SubscribeRequest(
135
+ symbol=contract.symbol,
136
+ exchange=contract.exchange
137
+ )
138
+ self.main_engine.subscribe(req, contract.gateway_name)
139
+
140
+ def buy(
141
+ self,
142
+ vt_symbol: str,
143
+ price: float,
144
+ volume: float,
145
+ order_type: OrderType = OrderType.LIMIT
146
+ ) -> str:
147
+ """"""
148
+ return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.OPEN, order_type)
149
+
150
+ def sell(
151
+ self,
152
+ vt_symbol: str,
153
+ price: float,
154
+ volume: float,
155
+ order_type: OrderType = OrderType.LIMIT
156
+ ) -> str:
157
+ """"""
158
+ return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.CLOSE, order_type)
159
+
160
+ def short(
161
+ self,
162
+ vt_symbol: str,
163
+ price: float,
164
+ volume: float,
165
+ order_type: OrderType = OrderType.LIMIT
166
+ ) -> str:
167
+ """"""
168
+ return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.OPEN, order_type)
169
+
170
+ def cover(
171
+ self,
172
+ vt_symbol: str,
173
+ price: float,
174
+ volume: float,
175
+ order_type: OrderType = OrderType.LIMIT
176
+ ) -> str:
177
+ """"""
178
+ return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.CLOSE, order_type)
179
+
180
+ def cancel_order(self, vt_orderid: str) -> None:
181
+ """"""
182
+ order: Optional[OrderData] = self.get_order(vt_orderid)
183
+ if not order:
184
+ return
185
+
186
+ req: CancelRequest = order.create_cancel_request()
187
+ self.main_engine.cancel_order(req, order.gateway_name)
188
+
189
+ def get_tick(self, vt_symbol: str, use_df: bool = False) -> Optional[TickData]:
190
+ """"""
191
+ return get_data(self.main_engine.get_tick, arg=vt_symbol, use_df=use_df)
192
+
193
+ def get_ticks(self, vt_symbols: Sequence[str], use_df: bool = False) -> Sequence[TickData]:
194
+ """"""
195
+ ticks: list = []
196
+ for vt_symbol in vt_symbols:
197
+ tick: Optional[TickData] = self.main_engine.get_tick(vt_symbol)
198
+ ticks.append(tick)
199
+
200
+ if not use_df:
201
+ return ticks
202
+ else:
203
+ return to_df(ticks)
204
+
205
+ def get_order(self, vt_orderid: str, use_df: bool = False) -> Optional[OrderData]:
206
+ """"""
207
+ return get_data(self.main_engine.get_order, arg=vt_orderid, use_df=use_df)
208
+
209
+ def get_orders(self, vt_orderids: Sequence[str], use_df: bool = False) -> Sequence[OrderData]:
210
+ """"""
211
+ orders: list = []
212
+ for vt_orderid in vt_orderids:
213
+ order: Optional[OrderData] = self.main_engine.get_order(vt_orderid)
214
+ orders.append(order)
215
+
216
+ if not use_df:
217
+ return orders
218
+ else:
219
+ return to_df(orders)
220
+
221
+ def get_trades(self, vt_orderid: str, use_df: bool = False) -> Sequence[TradeData]:
222
+ """"""
223
+ trades: list = []
224
+ all_trades: List[TradeData] = self.main_engine.get_all_trades()
225
+
226
+ for trade in all_trades:
227
+ if trade.vt_orderid == vt_orderid:
228
+ trades.append(trade)
229
+
230
+ if not use_df:
231
+ return trades
232
+ else:
233
+ return to_df(trades)
234
+
235
+ def get_all_active_orders(self, use_df: bool = False) -> Sequence[OrderData]:
236
+ """"""
237
+ return get_data(self.main_engine.get_all_active_orders, use_df=use_df)
238
+
239
+ def get_contract(self, vt_symbol, use_df: bool = False) -> Optional[ContractData]:
240
+ """"""
241
+ return get_data(self.main_engine.get_contract, arg=vt_symbol, use_df=use_df)
242
+
243
+ def get_all_contracts(self, use_df: bool = False) -> Sequence[ContractData]:
244
+ """"""
245
+ return get_data(self.main_engine.get_all_contracts, use_df=use_df)
246
+
247
+ def get_account(self, vt_accountid: str, use_df: bool = False) -> Optional[AccountData]:
248
+ """"""
249
+ return get_data(self.main_engine.get_account, arg=vt_accountid, use_df=use_df)
250
+
251
+ def get_all_accounts(self, use_df: bool = False) -> Sequence[AccountData]:
252
+ """"""
253
+ return get_data(self.main_engine.get_all_accounts, use_df=use_df)
254
+
255
+ def get_position(self, vt_positionid: str, use_df: bool = False) -> Optional[PositionData]:
256
+ """"""
257
+ return get_data(self.main_engine.get_position, arg=vt_positionid, use_df=use_df)
258
+
259
+ def get_position_(self, vt_symbol: str, direction: Direction, use_df: bool = False) -> PositionData:
260
+ """"""
261
+ contract: ContractData = self.main_engine.get_contract(vt_symbol)
262
+ if not contract:
263
+ return None
264
+
265
+ vt_positionid: str = f"{contract.gateway_name}.{contract.vt_symbol}.{direction.value}"
266
+ return get_data(self.main_engine.get_position, arg=vt_positionid, use_df=use_df)
267
+
268
+ def get_all_positions(self, use_df: bool = False) -> Sequence[PositionData]:
269
+ """"""
270
+ return get_data(self.main_engine.get_all_positions, use_df=use_df)
271
+
272
+ def get_bars(
273
+ self,
274
+ vt_symbol: str,
275
+ start_date: str,
276
+ interval: Interval,
277
+ use_df: bool = False
278
+ ) -> Sequence[BarData]:
279
+ """"""
280
+ contract: Optional[ContractData] = self.main_engine.get_contract(vt_symbol)
281
+ if not contract:
282
+ return []
283
+
284
+ start: datetime = datetime.strptime(start_date, "%Y%m%d")
285
+ end: datetime = datetime.now()
286
+
287
+ req: HistoryRequest = HistoryRequest(
288
+ symbol=contract.symbol,
289
+ exchange=contract.exchange,
290
+ start=start,
291
+ end=end,
292
+ interval=interval
293
+ )
294
+
295
+ return get_data(self.datafeed.query_bar_history, arg=req, use_df=use_df)
296
+
297
+ def write_log(self, msg: str) -> None:
298
+ """"""
299
+ log: LogData = LogData(msg=msg, gateway_name=APP_NAME)
300
+ print(f"{log.time}\t{log.msg}")
301
+
302
+ event: Event = Event(EVENT_SCRIPT_LOG, log)
303
+ self.event_engine.put(event)
304
+
305
+ def send_email(self, msg: str) -> None:
306
+ """"""
307
+ subject: str = "脚本策略引擎通知"
308
+ self.main_engine.send_email(subject, msg)
309
+
310
+
311
+ def to_df(data_list: Sequence) -> Optional[DataFrame]:
312
+ """"""
313
+ if not data_list:
314
+ return None
315
+
316
+ dict_list: list = [data.__dict__ for data in data_list if data]
317
+ return DataFrame(dict_list)
318
+
319
+
320
+ def get_data(func: callable, arg: Any = None, use_df: bool = False) -> Optional[BaseData]:
321
+ """"""
322
+ if not arg:
323
+ data = func()
324
+ else:
325
+ data = func(arg)
326
+
327
+ if not use_df:
328
+ return data
329
+ elif data is None:
330
+ return data
331
+ else:
332
+ if not isinstance(data, list):
333
+ data: list = [data]
334
+ return to_df(data)
@@ -0,0 +1 @@
1
+ from .widget import ScriptManager
Binary file
@@ -0,0 +1,103 @@
1
+ from pathlib import Path
2
+
3
+ from vnpy.event import EventEngine, Event
4
+ from vnpy.trader.engine import MainEngine
5
+ from vnpy.trader.ui import QtWidgets, QtCore
6
+ from vnpy.trader.object import LogData
7
+ from ..engine import APP_NAME, EVENT_SCRIPT_LOG, BaseEngine
8
+
9
+
10
+ class ScriptManager(QtWidgets.QWidget):
11
+ """"""
12
+ signal_log: QtCore.Signal = QtCore.Signal(Event)
13
+
14
+ def __init__(self, main_engine: MainEngine, event_engine: EventEngine) -> None:
15
+ """"""
16
+ super().__init__()
17
+
18
+ self.main_engine: MainEngine = main_engine
19
+ self.event_engine: EventEngine = event_engine
20
+
21
+ self.script_engine: BaseEngine = main_engine.get_engine(APP_NAME)
22
+
23
+ self.script_path: str = ""
24
+
25
+ self.init_ui()
26
+ self.register_event()
27
+
28
+ self.script_engine.init()
29
+
30
+ def init_ui(self) -> None:
31
+ """"""
32
+ self.setWindowTitle("脚本策略")
33
+
34
+ start_button: QtWidgets.QPushButton = QtWidgets.QPushButton("启动")
35
+ start_button.clicked.connect(self.start_script)
36
+
37
+ stop_button: QtWidgets.QPushButton = QtWidgets.QPushButton("停止")
38
+ stop_button.clicked.connect(self.stop_script)
39
+
40
+ select_button: QtWidgets.QPushButton = QtWidgets.QPushButton("打开")
41
+ select_button.clicked.connect(self.select_script)
42
+
43
+ self.strategy_line: QtWidgets.QLineEdit = QtWidgets.QLineEdit()
44
+
45
+ self.log_monitor: QtWidgets.QTextEdit = QtWidgets.QTextEdit()
46
+ self.log_monitor.setReadOnly(True)
47
+
48
+ clear_button: QtWidgets.QPushButton = QtWidgets.QPushButton("清空")
49
+ clear_button.clicked.connect(self.log_monitor.clear)
50
+
51
+ hbox: QtWidgets.QHBoxLayout = QtWidgets.QHBoxLayout()
52
+ hbox.addWidget(self.strategy_line)
53
+ hbox.addWidget(select_button)
54
+ hbox.addWidget(start_button)
55
+ hbox.addWidget(stop_button)
56
+ hbox.addStretch()
57
+ hbox.addWidget(clear_button)
58
+
59
+ vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
60
+ vbox.addLayout(hbox)
61
+ vbox.addWidget(self.log_monitor)
62
+
63
+ self.setLayout(vbox)
64
+
65
+ def register_event(self) -> None:
66
+ """"""
67
+ self.signal_log.connect(self.process_log_event)
68
+
69
+ self.event_engine.register(EVENT_SCRIPT_LOG, self.signal_log.emit)
70
+
71
+ def show(self) -> None:
72
+ """"""
73
+ self.showMaximized()
74
+
75
+ def process_log_event(self, event: Event) -> None:
76
+ """"""
77
+ log: LogData = event.data
78
+ msg: str = f"{log.time}\t{log.msg}"
79
+ self.log_monitor.append(msg)
80
+
81
+ def start_script(self) -> None:
82
+ """"""
83
+ if self.script_path:
84
+ self.script_engine.start_strategy(self.script_path)
85
+
86
+ def stop_script(self) -> None:
87
+ """"""
88
+ self.script_engine.stop_strategy()
89
+
90
+ def select_script(self) -> None:
91
+ """"""
92
+ cwd: str = str(Path.cwd())
93
+
94
+ path, type_ = QtWidgets.QFileDialog.getOpenFileName(
95
+ self,
96
+ u"载入策略脚本",
97
+ cwd,
98
+ "Python File(*.py)"
99
+ )
100
+
101
+ if path:
102
+ self.script_path = path
103
+ self.strategy_line.setText(path)
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: vnpy_scripttrader
3
+ Version: 1.0.3
4
+ Summary: Script trading application for VeighNa quant trading framework.
5
+ Home-page: https://www.vnpy.com
6
+ Author: Xiaoyou Chen
7
+ Author-email: xiaoyou.chen@mail.vnpy.com
8
+ License: MIT
9
+ Keywords: quant,quantitative,investment,trading,algotrading
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Office/Business :: Financial :: Investment
18
+ Classifier: Programming Language :: Python :: Implementation :: CPython
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Natural Language :: Chinese (Simplified)
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: importlib_metadata
24
+ Requires-Dist: pandas
25
+ Dynamic: license-file
26
+
27
+ # VeighNa框架的脚本交易模块
28
+
29
+ <p align="center">
30
+ <img src ="https://vnpy.oss-cn-shanghai.aliyuncs.com/vnpy-logo.png"/>
31
+ </p>
32
+
33
+ <p align="center">
34
+ <img src ="https://img.shields.io/badge/version-1.0.3-blueviolet.svg"/>
35
+ <img src ="https://img.shields.io/badge/platform-windows|linux|macos-yellow.svg"/>
36
+ <img src ="https://img.shields.io/badge/python-3.10|3.11|3.12|3.13-blue.svg" />
37
+ <img src ="https://img.shields.io/github/license/vnpy/vnpy.svg?color=orange"/>
38
+ </p>
39
+
40
+ ## 说明
41
+
42
+ ScriptTrader是用于交易脚本执行的功能模块,和其他策略模块最大的区别在于其基于【时间驱动】的【同步逻辑】,也支持在命令行(Jupyter Notebook)中以REPL指令形式的进行交易操作,该模块没有回测功能。
43
+
44
+ ## 安装
45
+
46
+ 安装环境推荐基于3.0.0版本以上的【[**VeighNa Studio**](https://www.vnpy.com)】。
47
+
48
+ 直接使用pip命令:
49
+
50
+ ```
51
+ pip install vnpy_scripttrader
52
+ ```
53
+
54
+
55
+ 或者下载源代码后,解压后在cmd中运行:
56
+
57
+ ```
58
+ pip install .
59
+ ```
@@ -0,0 +1,11 @@
1
+ vnpy_scripttrader/__init__.py,sha256=B0qi52oGJB42eUsAhWPcJNJO3xyFDv8LKxdnuD_kNOA,1824
2
+ vnpy_scripttrader/cli.py,sha256=Ecb2u73OhdbTI_N8U72cb4tWwl0RQfTwsQrhvIktEIc,855
3
+ vnpy_scripttrader/engine.py,sha256=c_ht81sw4dlVkHoPEZ4Qlj39i4wyR-noHkIee_DGHUk,10703
4
+ vnpy_scripttrader/ui/__init__.py,sha256=l2g2iQooT1OyWTbN-VmmOEDc5TLW_v419gpf5PMQIm0,35
5
+ vnpy_scripttrader/ui/script.ico,sha256=XtTNZE3gTPyXU7vgjY1JhdMCfWnIXc7KosZUvHmV5XQ,59966
6
+ vnpy_scripttrader/ui/widget.py,sha256=dl-pQpzvhDMZ4CyA_t3tvS9YGOUKrid5lF6DFHx4v_A,3207
7
+ vnpy_scripttrader-1.0.3.dist-info/licenses/LICENSE,sha256=PhdGUM_j-YTyaMqZFRcSqAUQU4nVwDzC4I1584GpKvg,1109
8
+ vnpy_scripttrader-1.0.3.dist-info/METADATA,sha256=ijlw_L68YmhBcnbq773Eo0faWDi1DeN0RsswCWp4Dok,2120
9
+ vnpy_scripttrader-1.0.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10
+ vnpy_scripttrader-1.0.3.dist-info/top_level.txt,sha256=bUEk6mw8-HRsoENuFWSPSzjTNlw_aUbJXUPW8GCq3U4,18
11
+ vnpy_scripttrader-1.0.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-present, Xiaoyou Chen
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.
@@ -0,0 +1 @@
1
+ vnpy_scripttrader