diff --git a/vnpy/trader/app/optionMaster/TradingCalendar.csv b/vnpy/trader/app/optionMaster/TradingCalendar.csv new file mode 100644 index 00000000..40b56ce6 --- /dev/null +++ b/vnpy/trader/app/optionMaster/TradingCalendar.csv @@ -0,0 +1,731 @@ +date,description +2017-11-09, +2017-11-10, +2017-11-11,weekend +2017-11-12,weekend +2017-11-13, +2017-11-14, +2017-11-15, +2017-11-16, +2017-11-17, +2017-11-18,weekend +2017-11-19,weekend +2017-11-20, +2017-11-21, +2017-11-22, +2017-11-23, +2017-11-24, +2017-11-25,weekend +2017-11-26,weekend +2017-11-27, +2017-11-28, +2017-11-29, +2017-11-30, +2017-12-01, +2017-12-02,weekend +2017-12-03,weekend +2017-12-04, +2017-12-05, +2017-12-06, +2017-12-07, +2017-12-08, +2017-12-09,weekend +2017-12-10,weekend +2017-12-11, +2017-12-12, +2017-12-13, +2017-12-14, +2017-12-15, +2017-12-16,weekend +2017-12-17,weekend +2017-12-18, +2017-12-19, +2017-12-20, +2017-12-21, +2017-12-22, +2017-12-23,weekend +2017-12-24,weekend +2017-12-25, +2017-12-26, +2017-12-27, +2017-12-28, +2017-12-29, +2017-12-30,weekend +2017-12-31,weekend +2018-01-01,holiday +2018-01-02, +2018-01-03, +2018-01-04, +2018-01-05, +2018-01-06,weekend +2018-01-07,weekend +2018-01-08, +2018-01-09, +2018-01-10, +2018-01-11, +2018-01-12, +2018-01-13,weekend +2018-01-14,weekend +2018-01-15, +2018-01-16, +2018-01-17, +2018-01-18, +2018-01-19, +2018-01-20,weekend +2018-01-21,weekend +2018-01-22, +2018-01-23, +2018-01-24, +2018-01-25, +2018-01-26, +2018-01-27,weekend +2018-01-28,weekend +2018-01-29, +2018-01-30, +2018-01-31, +2018-02-01, +2018-02-02, +2018-02-03,weekend +2018-02-04,weekend +2018-02-05, +2018-02-06, +2018-02-07, +2018-02-08, +2018-02-09, +2018-02-10,weekend +2018-02-11,weekend +2018-02-12, +2018-02-13, +2018-02-14, +2018-02-15, +2018-02-16, +2018-02-17,weekend +2018-02-18,weekend +2018-02-19, +2018-02-20, +2018-02-21, +2018-02-22, +2018-02-23, +2018-02-24,weekend +2018-02-25,weekend +2018-02-26, +2018-02-27, +2018-02-28, +2018-03-01, +2018-03-02, +2018-03-03,weekend +2018-03-04,weekend +2018-03-05, +2018-03-06, +2018-03-07, +2018-03-08, +2018-03-09, +2018-03-10,weekend +2018-03-11,weekend +2018-03-12, +2018-03-13, +2018-03-14, +2018-03-15, +2018-03-16, +2018-03-17,weekend +2018-03-18,weekend +2018-03-19, +2018-03-20, +2018-03-21, +2018-03-22, +2018-03-23, +2018-03-24,weekend +2018-03-25,weekend +2018-03-26, +2018-03-27, +2018-03-28, +2018-03-29, +2018-03-30, +2018-03-31,weekend +2018-04-01,weekend +2018-04-02, +2018-04-03, +2018-04-04, +2018-04-05, +2018-04-06, +2018-04-07,weekend +2018-04-08,weekend +2018-04-09, +2018-04-10, +2018-04-11, +2018-04-12, +2018-04-13, +2018-04-14,weekend +2018-04-15,weekend +2018-04-16, +2018-04-17, +2018-04-18, +2018-04-19, +2018-04-20, +2018-04-21,weekend +2018-04-22,weekend +2018-04-23, +2018-04-24, +2018-04-25, +2018-04-26, +2018-04-27, +2018-04-28,weekend +2018-04-29,weekend +2018-04-30, +2018-05-01, +2018-05-02, +2018-05-03, +2018-05-04, +2018-05-05,weekend +2018-05-06,weekend +2018-05-07, +2018-05-08, +2018-05-09, +2018-05-10, +2018-05-11, +2018-05-12,weekend +2018-05-13,weekend +2018-05-14, +2018-05-15, +2018-05-16, +2018-05-17, +2018-05-18, +2018-05-19,weekend +2018-05-20,weekend +2018-05-21, +2018-05-22, +2018-05-23, +2018-05-24, +2018-05-25, +2018-05-26,weekend +2018-05-27,weekend +2018-05-28, +2018-05-29, +2018-05-30, +2018-05-31, +2018-06-01, +2018-06-02,weekend +2018-06-03,weekend +2018-06-04, +2018-06-05, +2018-06-06, +2018-06-07, +2018-06-08, +2018-06-09,weekend +2018-06-10,weekend +2018-06-11, +2018-06-12, +2018-06-13, +2018-06-14, +2018-06-15, +2018-06-16,weekend +2018-06-17,weekend +2018-06-18, +2018-06-19, +2018-06-20, +2018-06-21, +2018-06-22, +2018-06-23,weekend +2018-06-24,weekend +2018-06-25, +2018-06-26, +2018-06-27, +2018-06-28, +2018-06-29, +2018-06-30,weekend +2018-07-01,weekend +2018-07-02, +2018-07-03, +2018-07-04, +2018-07-05, +2018-07-06, +2018-07-07,weekend +2018-07-08,weekend +2018-07-09, +2018-07-10, +2018-07-11, +2018-07-12, +2018-07-13, +2018-07-14,weekend +2018-07-15,weekend +2018-07-16, +2018-07-17, +2018-07-18, +2018-07-19, +2018-07-20, +2018-07-21,weekend +2018-07-22,weekend +2018-07-23, +2018-07-24, +2018-07-25, +2018-07-26, +2018-07-27, +2018-07-28,weekend +2018-07-29,weekend +2018-07-30, +2018-07-31, +2018-08-01, +2018-08-02, +2018-08-03, +2018-08-04,weekend +2018-08-05,weekend +2018-08-06, +2018-08-07, +2018-08-08, +2018-08-09, +2018-08-10, +2018-08-11,weekend +2018-08-12,weekend +2018-08-13, +2018-08-14, +2018-08-15, +2018-08-16, +2018-08-17, +2018-08-18,weekend +2018-08-19,weekend +2018-08-20, +2018-08-21, +2018-08-22, +2018-08-23, +2018-08-24, +2018-08-25,weekend +2018-08-26,weekend +2018-08-27, +2018-08-28, +2018-08-29, +2018-08-30, +2018-08-31, +2018-09-01,weekend +2018-09-02,weekend +2018-09-03, +2018-09-04, +2018-09-05, +2018-09-06, +2018-09-07, +2018-09-08,weekend +2018-09-09,weekend +2018-09-10, +2018-09-11, +2018-09-12, +2018-09-13, +2018-09-14, +2018-09-15,weekend +2018-09-16,weekend +2018-09-17, +2018-09-18, +2018-09-19, +2018-09-20, +2018-09-21, +2018-09-22,weekend +2018-09-23,weekend +2018-09-24, +2018-09-25, +2018-09-26, +2018-09-27, +2018-09-28, +2018-09-29,weekend +2018-09-30,weekend +2018-10-01, +2018-10-02, +2018-10-03, +2018-10-04, +2018-10-05, +2018-10-06,weekend +2018-10-07,weekend +2018-10-08, +2018-10-09, +2018-10-10, +2018-10-11, +2018-10-12, +2018-10-13,weekend +2018-10-14,weekend +2018-10-15, +2018-10-16, +2018-10-17, +2018-10-18, +2018-10-19, +2018-10-20,weekend +2018-10-21,weekend +2018-10-22, +2018-10-23, +2018-10-24, +2018-10-25, +2018-10-26, +2018-10-27,weekend +2018-10-28,weekend +2018-10-29, +2018-10-30, +2018-10-31, +2018-11-01, +2018-11-02, +2018-11-03,weekend +2018-11-04,weekend +2018-11-05, +2018-11-06, +2018-11-07, +2018-11-08, +2018-11-09, +2018-11-10,weekend +2018-11-11,weekend +2018-11-12, +2018-11-13, +2018-11-14, +2018-11-15, +2018-11-16, +2018-11-17,weekend +2018-11-18,weekend +2018-11-19, +2018-11-20, +2018-11-21, +2018-11-22, +2018-11-23, +2018-11-24,weekend +2018-11-25,weekend +2018-11-26, +2018-11-27, +2018-11-28, +2018-11-29, +2018-11-30, +2018-12-01,weekend +2018-12-02,weekend +2018-12-03, +2018-12-04, +2018-12-05, +2018-12-06, +2018-12-07, +2018-12-08,weekend +2018-12-09,weekend +2018-12-10, +2018-12-11, +2018-12-12, +2018-12-13, +2018-12-14, +2018-12-15,weekend +2018-12-16,weekend +2018-12-17, +2018-12-18, +2018-12-19, +2018-12-20, +2018-12-21, +2018-12-22,weekend +2018-12-23,weekend +2018-12-24, +2018-12-25, +2018-12-26, +2018-12-27, +2018-12-28, +2018-12-29,weekend +2018-12-30,weekend +2018-12-31, +2019-01-01, +2019-01-02, +2019-01-03, +2019-01-04, +2019-01-05,weekend +2019-01-06,weekend +2019-01-07, +2019-01-08, +2019-01-09, +2019-01-10, +2019-01-11, +2019-01-12,weekend +2019-01-13,weekend +2019-01-14, +2019-01-15, +2019-01-16, +2019-01-17, +2019-01-18, +2019-01-19,weekend +2019-01-20,weekend +2019-01-21, +2019-01-22, +2019-01-23, +2019-01-24, +2019-01-25, +2019-01-26,weekend +2019-01-27,weekend +2019-01-28, +2019-01-29, +2019-01-30, +2019-01-31, +2019-02-01, +2019-02-02,weekend +2019-02-03,weekend +2019-02-04, +2019-02-05, +2019-02-06, +2019-02-07, +2019-02-08, +2019-02-09,weekend +2019-02-10,weekend +2019-02-11, +2019-02-12, +2019-02-13, +2019-02-14, +2019-02-15, +2019-02-16,weekend +2019-02-17,weekend +2019-02-18, +2019-02-19, +2019-02-20, +2019-02-21, +2019-02-22, +2019-02-23,weekend +2019-02-24,weekend +2019-02-25, +2019-02-26, +2019-02-27, +2019-02-28, +2019-03-01, +2019-03-02,weekend +2019-03-03,weekend +2019-03-04, +2019-03-05, +2019-03-06, +2019-03-07, +2019-03-08, +2019-03-09,weekend +2019-03-10,weekend +2019-03-11, +2019-03-12, +2019-03-13, +2019-03-14, +2019-03-15, +2019-03-16,weekend +2019-03-17,weekend +2019-03-18, +2019-03-19, +2019-03-20, +2019-03-21, +2019-03-22, +2019-03-23,weekend +2019-03-24,weekend +2019-03-25, +2019-03-26, +2019-03-27, +2019-03-28, +2019-03-29, +2019-03-30,weekend +2019-03-31,weekend +2019-04-01, +2019-04-02, +2019-04-03, +2019-04-04, +2019-04-05, +2019-04-06,weekend +2019-04-07,weekend +2019-04-08, +2019-04-09, +2019-04-10, +2019-04-11, +2019-04-12, +2019-04-13,weekend +2019-04-14,weekend +2019-04-15, +2019-04-16, +2019-04-17, +2019-04-18, +2019-04-19, +2019-04-20,weekend +2019-04-21,weekend +2019-04-22, +2019-04-23, +2019-04-24, +2019-04-25, +2019-04-26, +2019-04-27,weekend +2019-04-28,weekend +2019-04-29, +2019-04-30, +2019-05-01, +2019-05-02, +2019-05-03, +2019-05-04,weekend +2019-05-05,weekend +2019-05-06, +2019-05-07, +2019-05-08, +2019-05-09, +2019-05-10, +2019-05-11,weekend +2019-05-12,weekend +2019-05-13, +2019-05-14, +2019-05-15, +2019-05-16, +2019-05-17, +2019-05-18,weekend +2019-05-19,weekend +2019-05-20, +2019-05-21, +2019-05-22, +2019-05-23, +2019-05-24, +2019-05-25,weekend +2019-05-26,weekend +2019-05-27, +2019-05-28, +2019-05-29, +2019-05-30, +2019-05-31, +2019-06-01,weekend +2019-06-02,weekend +2019-06-03, +2019-06-04, +2019-06-05, +2019-06-06, +2019-06-07, +2019-06-08,weekend +2019-06-09,weekend +2019-06-10, +2019-06-11, +2019-06-12, +2019-06-13, +2019-06-14, +2019-06-15,weekend +2019-06-16,weekend +2019-06-17, +2019-06-18, +2019-06-19, +2019-06-20, +2019-06-21, +2019-06-22,weekend +2019-06-23,weekend +2019-06-24, +2019-06-25, +2019-06-26, +2019-06-27, +2019-06-28, +2019-06-29,weekend +2019-06-30,weekend +2019-07-01, +2019-07-02, +2019-07-03, +2019-07-04, +2019-07-05, +2019-07-06,weekend +2019-07-07,weekend +2019-07-08, +2019-07-09, +2019-07-10, +2019-07-11, +2019-07-12, +2019-07-13,weekend +2019-07-14,weekend +2019-07-15, +2019-07-16, +2019-07-17, +2019-07-18, +2019-07-19, +2019-07-20,weekend +2019-07-21,weekend +2019-07-22, +2019-07-23, +2019-07-24, +2019-07-25, +2019-07-26, +2019-07-27,weekend +2019-07-28,weekend +2019-07-29, +2019-07-30, +2019-07-31, +2019-08-01, +2019-08-02, +2019-08-03,weekend +2019-08-04,weekend +2019-08-05, +2019-08-06, +2019-08-07, +2019-08-08, +2019-08-09, +2019-08-10,weekend +2019-08-11,weekend +2019-08-12, +2019-08-13, +2019-08-14, +2019-08-15, +2019-08-16, +2019-08-17,weekend +2019-08-18,weekend +2019-08-19, +2019-08-20, +2019-08-21, +2019-08-22, +2019-08-23, +2019-08-24,weekend +2019-08-25,weekend +2019-08-26, +2019-08-27, +2019-08-28, +2019-08-29, +2019-08-30, +2019-08-31,weekend +2019-09-01,weekend +2019-09-02, +2019-09-03, +2019-09-04, +2019-09-05, +2019-09-06, +2019-09-07,weekend +2019-09-08,weekend +2019-09-09, +2019-09-10, +2019-09-11, +2019-09-12, +2019-09-13, +2019-09-14,weekend +2019-09-15,weekend +2019-09-16, +2019-09-17, +2019-09-18, +2019-09-19, +2019-09-20, +2019-09-21,weekend +2019-09-22,weekend +2019-09-23, +2019-09-24, +2019-09-25, +2019-09-26, +2019-09-27, +2019-09-28,weekend +2019-09-29,weekend +2019-09-30, +2019-10-01, +2019-10-02, +2019-10-03, +2019-10-04, +2019-10-05,weekend +2019-10-06,weekend +2019-10-07, +2019-10-08, +2019-10-09, +2019-10-10, +2019-10-11, +2019-10-12,weekend +2019-10-13,weekend +2019-10-14, +2019-10-15, +2019-10-16, +2019-10-17, +2019-10-18, +2019-10-19,weekend +2019-10-20,weekend +2019-10-21, +2019-10-22, +2019-10-23, +2019-10-24, +2019-10-25, +2019-10-26,weekend +2019-10-27,weekend +2019-10-28, +2019-10-29, +2019-10-30, +2019-10-31, +2019-11-01, +2019-11-02,weekend +2019-11-03,weekend +2019-11-04, +2019-11-05, +2019-11-06, +2019-11-07, +2019-11-08, diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index 6ccdfd8f..d740b0a4 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -6,7 +6,7 @@ from collections import OrderedDict from vnpy.trader.vtConstant import * from vnpy.trader.vtObject import VtTickData -from .omFunction import getTimeToMaturity +from .omDate import getTimeToMaturity # 常量定义 diff --git a/vnpy/trader/app/optionMaster/omDate.py b/vnpy/trader/app/optionMaster/omDate.py new file mode 100644 index 00000000..1211c166 --- /dev/null +++ b/vnpy/trader/app/optionMaster/omDate.py @@ -0,0 +1,252 @@ +# encoding: UTF-8 + +"""用于处理周末和节假日,以计算交易日的组件""" + +from __future__ import division + +import csv +import datetime +import sys +import os +from collections import OrderedDict + +from vnpy.trader.uiQt import QtCore, QtWidgets, QtGui + + +# 常量定义 +ANNUAL_TRADINGDAYS = 240 + +CALENDAR_FILENAME = 'TradingCalendar.csv' +PATH = os.path.abspath(os.path.dirname(__file__)) +CALENDAR_FILEPATH = os.path.join(PATH, CALENDAR_FILENAME) + +# 加载日历数据 +try: + with open(CALENDAR_FILEPATH, 'r') as f: + reader = csv.DictReader(f) + CALENDAR = [d for d in reader] +except IOError: + CALENDAR = [] + +# TimeToMaturity缓存字典 +TTM_DICT = {} # key:date, value:float time(year) + + +######################################################################## +class CalendarEditor(QtWidgets.QTableWidget): + """日历编辑器""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + super(CalendarEditor, self).__init__() + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setColumnCount(2) + self.horizontalHeader().setVisible(True) # 关闭左边的垂直表头 + self.verticalHeader().setVisible(False) # 关闭左边的垂直表头 + self.setHorizontalHeaderLabels([u'日期', u'描述']) + + #---------------------------------------------------------------------- + def clearTable(self): + """清空表格""" + self.clear() + self.initUi() + + #---------------------------------------------------------------------- + def loadCalendar(self): + """读取日历""" + self.clearContents() + + row = 0 + totalRow = self.rowCount() + + # 如果有则打开 + try: + with open(CALENDAR_FILEPATH, 'r') as f: + reader = csv.DictReader(f) + for d in reader: + cellDate = QtWidgets.QTableWidgetItem(d['date']) + cellDescription = QtWidgets.QTableWidgetItem(d['description']) + + if row >= totalRow: + self.insertRow(row) + + self.setItem(row, 0, cellDate) + self.setItem(row, 1, cellDescription) + + row = row + 1 + + # 如果没有该文件则创建 + except IOError: + f = open(CALENDAR_FILEPATH, 'w') + f.close() + + #---------------------------------------------------------------------- + def saveCalendar(self): + """保存日历""" + totalRow = self.rowCount() + + with open(CALENDAR_FILEPATH, 'w') as f: + writer = csv.DictWriter(f, lineterminator='\n', fieldnames=['date', 'description']) + writer.writeheader() + + for row in range(totalRow): + cellDate = self.item(row, 0) + cellDescription = self.item(row, 1) + + if cellDescription: + description = cellDescription.text() + else: + description = '' + + d = { + 'date': cellDate.text(), + 'description': description + } + writer.writerow(d) + + #---------------------------------------------------------------------- + def initCalendar(self): + """初始化日历""" + initCalendarCsv() + + +######################################################################## +class CalendarManager(QtWidgets.QWidget): + """日历管理组件""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + super(CalendarManager, self).__init__() + self.initUI() + + #---------------------------------------------------------------------- + def initUI(self): + """""" + self.setWindowTitle(u'日历管理') + + self.editor = CalendarEditor() + + buttonLoad = QtWidgets.QPushButton(u'读取日历') + buttonSave = QtWidgets.QPushButton(u'保存日历') + buttonInit = QtWidgets.QPushButton(u'初始化日历') + buttonClear = QtWidgets.QPushButton(u'清空') + + buttonLoad.clicked.connect(self.editor.loadCalendar) + buttonSave.clicked.connect(self.editor.saveCalendar) + buttonInit.clicked.connect(self.editor.initCalendar) + buttonClear.clicked.connect(self.editor.clearTable) + + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(buttonLoad) + hbox.addWidget(buttonSave) + hbox.addWidget(buttonInit) + hbox.addWidget(buttonClear) + hbox.addStretch() + + vbox = QtWidgets.QVBoxLayout() + vbox.addLayout(hbox) + vbox.addWidget(self.editor) + + self.setLayout(vbox) + + +#---------------------------------------------------------------------- +def runCalendarEditor(): + """运行日历编辑器""" + reload(sys) + sys.setdefaultencoding('utf8') + + app = QtWidgets.QApplication(sys.argv) + app.setFont(QtGui.QFont(u'微软雅黑', 12)) + + try: + import qdarkstyle + app.setStyleSheet(qdarkstyle.load_stylesheet(pyside=False)) + except: + pass + + manager = CalendarManager() + manager.showMaximized() + + sys.exit(app.exec_()) + + +#---------------------------------------------------------------------- +def initCalendarCsv(): + """初始化日期文件""" + # 读取csv中的数据并生成列表和字典 + calendarDict = OrderedDict() + + try: + with open(CALENDAR_FILEPATH, 'r') as f: + reader = csv.DictReader(f) + for d in reader: + calendarDict[d['date']] = d + except IOError: + pass + + # 生成未来的数据 + today = datetime.date.today() + oneday = datetime.timedelta(days=1) + + t = today + for i in range(365*2): + # 如果日历里没有该日期的状态,则初始化(仅判断是否周末) + tstr = t.strftime('%Y-%m-%d') + if tstr not in calendarDict: + if t.weekday() == 5 or t.weekday() == 6: + description = 'weekend' + else: + description = '' + d = { + 'date': tstr, + 'description': description + } + calendarDict[d['date']] = d + + # 往下一天 + t = t + oneday + + # 保存到csv中 + with open(CALENDAR_FILEPATH, 'w') as f: + writer = csv.DictWriter(f, lineterminator='\n', fieldnames=d.keys()) + writer.writeheader() + for d in calendarDict.values(): + writer.writerow(d) + + +#---------------------------------------------------------------------- +def getTimeToMaturity(expiryDate): + """计算剩余的年化到期时间(交易日)""" + # 如果有缓存则直接返回 + if expiryDate in TTM_DICT: + return TTM_DICT[expiryDate] + + # 获取日期对象 + expiryDt = datetime.datetime.strptime(expiryDate, '%Y%m%d').date() + todayDt = datetime.date.today() + + tradingDays = 0 + for d in CALENDAR: + dt = datetime.datetime.strptime(d['date'], '%Y-%m-%d').date() + # 判断是否为交易日的条件: + # 1. 日期大于等于今日 + # 2. 日期小于等于到期日 + # 3. 日期没有描述(假期) + if dt>=todayDt and dt<=expiryDt and not d['description']: + tradingDays += 1 + + # 缓存并返回年化剩余时间 + ttm = tradingDays/ANNUAL_TRADINGDAYS + TTM_DICT[expiryDate] = ttm + return ttm + + +if __name__ == '__main__': + runCalendarEditor() \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/omFunction.py b/vnpy/trader/app/optionMaster/omFunction.py deleted file mode 100644 index 4a8fe71d..00000000 --- a/vnpy/trader/app/optionMaster/omFunction.py +++ /dev/null @@ -1,9 +0,0 @@ -# encoding: UTF-8 - - -#---------------------------------------------------------------------- -def getTimeToMaturity(expiryDate): - """计算期权剩余到期时间""" - t = 0 - return t - \ No newline at end of file