# 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(15, 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_()