From fa2ce167eed669fbdbe6c56efa93a59a06a9d6cd Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Thu, 6 Dec 2018 16:12:58 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9E=E5=9B=BE=E5=BD=A2?= =?UTF-8?q?=E5=8C=96=E7=9A=84RQData=E6=95=B0=E6=8D=AE=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataService/RqdataDataService/config.json | 10 +- examples/DataService/RqdataDataService/run.py | 274 ++++++++++++++++++ .../DataService/RqdataDataService/vnpy.ico | Bin 0 -> 67646 bytes vnpy/trader/app/ctaStrategy/ctaEngine.py | 7 +- vnpy/trader/vtEngine.py | 2 +- 5 files changed, 280 insertions(+), 13 deletions(-) create mode 100644 examples/DataService/RqdataDataService/run.py create mode 100644 examples/DataService/RqdataDataService/vnpy.ico diff --git a/examples/DataService/RqdataDataService/config.json b/examples/DataService/RqdataDataService/config.json index 6c85451a..8780a990 100644 --- a/examples/DataService/RqdataDataService/config.json +++ b/examples/DataService/RqdataDataService/config.json @@ -1,9 +1,5 @@ { - "MONGO_HOST": "localhost", - "MONGO_PORT": 27017, - - "SYMBOLS": ["510050", "510300"], - - "USERNAME": "", - "PASSWORD": "" + "rqUsername": "", + "rqPassword": "", + "product": ["IF"] } \ No newline at end of file diff --git a/examples/DataService/RqdataDataService/run.py b/examples/DataService/RqdataDataService/run.py new file mode 100644 index 00000000..774e95b3 --- /dev/null +++ b/examples/DataService/RqdataDataService/run.py @@ -0,0 +1,274 @@ +# encoding: UTF-8 + +from __future__ import print_function + +import json +import ctypes +from datetime import datetime, timedelta, time +from time import sleep +from threading import Thread +from collections import OrderedDict + +import qdarkstyle +from pymongo import MongoClient, ASCENDING, DESCENDING +from pymongo.errors import ConnectionFailure + +from vnpy.trader.uiQt import QtCore, QtWidgets, QtGui +from vnpy.trader.vtObject import VtBarData +from vnpy.trader.app.ctaStrategy.ctaBase import MINUTE_DB_NAME, DAILY_DB_NAME + + +DAY_START = time(9, 0) # 日盘启动和停止时间 +DAY_END = time(17, 15) +NIGHT_START = time(21, 0) # 夜盘启动和停止时间 +NIGHT_END = time(2, 30) + + +######################################################################## +class RqDataManager(QtWidgets.QWidget): + """""" + signal = QtCore.Signal(str) + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + super(RqDataManager, self).__init__() + + self.client = None + self.rq = None + self.thread = Thread(target=self.run) + + self.productList = [] + self.symbolExchangeDict = OrderedDict() + + self.initUi() + + n1 = self.connectMongo() + if not n1: + return + + n2 = self.initRqData() + if not n2: + return + + self.count = 0 + self.active = True + self.thread.start() + + #---------------------------------------------------------------------- + def connectMongo(self): + """连接数据库""" + try: + self.client = MongoClient(serverSelectionTimeoutMS=10) + self.client.server_info() + self.writeLog(u'MongoDB连接成功') + return True + except ConnectionFailure: + self.client = None + self.writeLog(u'MongoDB连接失败') + return False + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setWindowTitle(u'RQData数据服务') + self.setWindowIcon(QtGui.QIcon('vnpy.ico')) + + self.setFixedHeight(500) + self.setFixedWidth(900) + + self.logMonitor = QtWidgets.QTextEdit() + self.logMonitor.setReadOnly(True) + + vbox = QtWidgets.QVBoxLayout() + vbox.addWidget(self.logMonitor) + self.setLayout(vbox) + + self.signal.connect(self.updateLog) + + # 托盘配置 + self.tray = QtWidgets.QSystemTrayIcon() + self.tray.setIcon(QtGui.QIcon('vnpy.ico')) + self.tray.activated.connect(self.showManager) + + restoreAction = QtWidgets.QAction(u'还原', self, triggered=self.show) + quitAction = QtWidgets.QAction(u'退出', self, triggered=self.exit) + + menu = QtWidgets.QMenu(QtWidgets.QApplication.desktop()) + menu.addAction(restoreAction) + menu.addAction(quitAction) + self.tray.setContextMenu(menu) + + self.tray.show() + + #---------------------------------------------------------------------- + def initRqData(self): + """""" + with open('config.json') as config: + setting = json.load(config) + + for product in setting['product']: + self.productList.append(product.upper()) + + # 检查是否填写了RQData配置 + username = setting.get('rqUsername', None) + password = setting.get('rqPassword', None) + if not username or not password: + self.writeLog(u'RQData的用户名和密码配置错误,请在config.json中修改') + return False + + # 加载RQData + try: + import rqdatac as rq + except ImportError: + self.writeLog(u'没有安装RQData客户端,请先安装rqdatac') + return False + + # 登录RQData + self.rq = rq + self.rq.init(username, password) + + # 获取本日可交易合约代码 + try: + df = self.rq.all_instruments(type='Future', date=datetime.now()) + for ix, row in df.iterrows(): + self.symbolExchangeDict[row['order_book_id']] = row['exchange'] + except RuntimeError: + self.writeLog(u'RQData的用户名和密码无效,请联系米筐申请试用或者购买') + return False + + self.writeLog(u'RQData客户端登录成功') + return True + + #---------------------------------------------------------------------- + def downloadBar(self, symbol, frequency): + """下载合约数据""" + if 'frequency' == '1m': + db = self.client[MINUTE_DB_NAME] + else: + db = self.client[DAILY_DB_NAME] + + # 上期所和大商所代码改为小写 + exchange = self.symbolExchangeDict[symbol] + if exchange in ['SHFE', 'DCE']: + localSymbol = symbol.lower() + else: + localSymbol = symbol + collection = db[localSymbol] + + # 获取本地数据库中最后一条记录的时间,并下载新数据 + result = collection.find_one(sort=[("datetime", DESCENDING)]) + if result: + startDate = result['datetime'] + else: + startDate = '20180101' + + if startDate: + self.writeLog(u'%s下载更新数据,开始时间:%s' %(localSymbol, startDate)) + else: + self.writeLog(u'%s初次下载数据,耗时可能较长,请耐心等待' %(localSymbol)) + + df = self.rq.get_price(symbol, + frequency=frequency, + fields=['open', 'high', 'low', 'close', 'volume'], + start_date=startDate, + end_date=datetime.now()) + + # 插入到数据库 + for ix, row in df.iterrows(): + bar = self.generateBar(row, localSymbol) + d = bar.__dict__ + flt = {'datetime': bar.datetime} + collection.replace_one(flt, d, True) + + self.writeLog(u'%s数据更新完成:%s - %s' %(localSymbol, df.index[0], df.index[-1])) + + #---------------------------------------------------------------------- + def generateBar(self, row, symbol): + """生成K线对象""" + bar = VtBarData() + + bar.symbol = symbol + bar.vtSymbol = symbol + bar.open = row['open'] + bar.high = row['high'] + bar.low = row['low'] + bar.close = row['close'] + bar.volume = row['volume'] + bar.datetime = row.name + bar.date = bar.datetime.strftime("%Y%m%d") + bar.time = bar.datetime.strftime("%H:%M:%S") + + return bar + + #---------------------------------------------------------------------- + def writeLog(self, msg): + """记录日志""" + self.signal.emit(msg) + + #---------------------------------------------------------------------- + def updateLog(self, msg): + """更新日志""" + dt = datetime.now() + msg = '%s: %s' %(dt, msg) + self.logMonitor.append(msg) + + #---------------------------------------------------------------------- + def run(self): + """运行""" + while self.active: + sleep(1) + + self.count += 1 + if self.count < 10: + continue + self.count = 0 + + now = datetime.now().time() + if ((DAY_START <= now <= DAY_END) or + (now >= NIGHT_START) or + (now <= NIGHT_END)): + for symbol in self.symbolExchangeDict.keys(): + download = False + for product in self.productList: + if product in symbol: + download = True + + if download: + self.downloadBar(symbol, '1m') + else: + self.writeLog(u'非交易时间段,不执行更新') + + #---------------------------------------------------------------------- + def showManager(self, reason): + """""" + self.show() + + #---------------------------------------------------------------------- + def closeEvent(self, event): + """""" + self.hide() + event.ignore() + + #---------------------------------------------------------------------- + def exit(self): + """""" + self.active = False + self.thread.join() + + QtWidgets.qApp.quit() + + +if __name__ == '__main__': + font = QtGui.QFont(u'微软雅黑', 12) + + app = QtWidgets.QApplication([]) + app.setFont(font) + app.setStyleSheet(qdarkstyle.load_stylesheet_from_environment()) + + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('RQDataService') + + manager = RqDataManager() + manager.show() + + app.exec_() \ No newline at end of file diff --git a/examples/DataService/RqdataDataService/vnpy.ico b/examples/DataService/RqdataDataService/vnpy.ico new file mode 100644 index 0000000000000000000000000000000000000000..f5146d56ddaa2bfd38768598803f5019593fcd33 GIT binary patch literal 67646 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 literal 0 HcmV?d00001 diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index 0991d41b..385bb6eb 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -683,17 +683,15 @@ class CtaEngine(AppEngine): def initRqData(self): """初始化RQData客户端""" # 检查是否填写了RQData配置 - username = globalSetting.get('rqUsername') - password = globalSetting.get('rqPassword') + username = globalSetting.get('rqUsername', None) + password = globalSetting.get('rqPassword', None) if not username or not password: - print globalSetting return # 加载RQData try: import rqdatac as rq except ImportError: - print 'import fail' return # 登录RQData @@ -706,7 +704,6 @@ class CtaEngine(AppEngine): for ix, row in df.iterrows(): self.rqSymbolSet.add(row['order_book_id']) except RuntimeError: - print 'download fail' pass #---------------------------------------------------------------------- diff --git a/vnpy/trader/vtEngine.py b/vnpy/trader/vtEngine.py index f824957c..c910c555 100644 --- a/vnpy/trader/vtEngine.py +++ b/vnpy/trader/vtEngine.py @@ -198,7 +198,7 @@ class MainEngine(object): # 读取MongoDB的设置 try: # 设置MongoDB操作的超时时间为0.5秒 - self.dbClient = MongoClient(globalSetting['mongoHost'], globalSetting['mongoPort'], serverSelectionTimeoutMS=500) + self.dbClient = MongoClient(globalSetting['mongoHost'], globalSetting['mongoPort'], serverSelectionTimeoutMS=10) # 调用server_info查询服务器状态,防止服务器异常并未连接成功 self.dbClient.server_info()