class HistWindowSelect(QGroupBox): """An extension of the QGroupBox widget. It allows the user to select a start date and end date for the historical window in the Monte Carlo VaR calculation application. The end date of the historical window is set to 22 days from the start date as a minimum. This restriction is implemented through the QDateEdit's set minimum date function. """ end_signal = QtCore.pyqtSignal(dt.datetime) def __init__(self, parent=None): super(HistWindowSelect, self).__init__(parent) self.setTitle('Historical Window Select') grid = QGridLayout() lbl_start = QLabel('Start Date: ') lbl_end = QLabel('End Date: ') self.deStart = QDateEdit() self.deStart.setCalendarPopup(True) self.deStart.setMinimumDateTime(dt.datetime(2015, 1, 1)) self.deStart.setMaximumDateTime( self.getWeekdaysBack(dt.datetime.now(), 22)) self.deStart.dateChanged.connect(self.onStartDateChange) self.deEnd = QDateEdit() self.deEnd.setCalendarPopup(True) self.deEnd.setMaximumDateTime(dt.datetime.now()) self.deEnd.dateChanged.connect(self.onEndDateChange) self.setEndDateMinimum() lbl_disc = QLabel( 'Note: A minimum historical window length <br>of 22 business days has been imposed.' ) grid.addWidget(lbl_start, 0, 0) grid.addWidget(lbl_end, 1, 0) grid.addWidget(self.deStart, 0, 1) grid.addWidget(self.deEnd, 1, 1) grid.addWidget(lbl_disc, 2, 1) self.setLayout(grid) def onStartDateChange(self): """Checks if new start date is a weekend. If so, it adds the appropriate number of days to bring the start date to the following Monday. After, it updates the minimum value of the end date, which must be 22 business days after the start date. """ deStart = dt.datetime.combine(self.deStart.date().toPyDate(), dt.datetime.min.time()) if deStart.weekday() == 5: deStart = deStart + timedelta(days=2) elif deStart.weekday() == 6: deStart = deStart + timedelta(days=1) self.deStart.setDate(deStart) self.setEndDateMinimum() def setEndDateMinimum(self): """Updates the minimum value of the end date, which must be 22 business days after the start date. """ deStart = dt.datetime.combine(self.deStart.date().toPyDate(), dt.datetime.min.time()) end_min = self.getWeekdaysOut(deStart, 22) self.deEnd.setMinimumDateTime(end_min) if self.deEnd.date() < end_min: self.deEnd.setDate(end_min) self.test_signal.emit(end_min) def onEndDateChange(self): """Checks if new end date is a weekend. If so, it adds the appropriate number of days to bring the end date to the following Monday. After, it emits a signal containing the new end date to be picked up by a slot in the PredWindowSelect widget. """ deEnd = dt.datetime.combine(self.deEnd.date().toPyDate(), dt.datetime.min.time()) if deEnd.weekday() == 5: deEnd = deEnd + timedelta(days=2) elif deEnd.weekday() == 6: deEnd = deEnd + timedelta(days=1) self.deEnd.setDate(deEnd) self.end_signal.emit(deEnd) def getWeekdaysOut(self, start_date, days_out): """Finds the date that is x weekdays later than the start date (where x = days_out). Args: start_date (datetime.datetime) - Start date from which to count weekdays out. days_out (int) - Number of days out. Returns: curr_date (datetime.datetime) - the date that is days_out weekdays later than start_date. Raises Error: None """ if start_date.weekday() == 5: start_date += timedelta(days=2) if start_date.weekday() == 6: start_date += timedelta(days=1) for i in range(days_out): if i == 0: curr_date = start_date next_date = curr_date + timedelta(days=1) if next_date.weekday() == 5: next_date = curr_date + timedelta(days=3) curr_date = next_date return (curr_date) def getWeekdaysBack(self, start_date, days_back): """Finds the date that is x weekdays earlier than the start date (where x = days_back). Args: start_date (datetime.datetime) - Start date from which to count weekdays out. days_back (int) - Number of days back. Returns: curr_date (datetime.datetime) - the date that is days_back weekdays earlier than start_date. Raises Error: None """ if start_date.weekday() == 5: start_date -= timedelta(days=1) if start_date.weekday() == 6: start_date -= timedelta(days=2) for i in range(days_back): if i == 0: curr_date = start_date next_date = curr_date - timedelta(days=1) if next_date.weekday() == 6: next_date = curr_date - timedelta(days=3) curr_date = next_date return (curr_date) def getDateWindow(self): """Getter function for the date window selected by the user. """ start_date = dt.datetime.combine(self.deStart.date().toPyDate(), dt.datetime.min.time()) end_date = dt.datetime.combine(self.deEnd.date().toPyDate(), dt.datetime.min.time()) return start_date, end_date
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.textSuffix = QTextEdit(self.centralwidget) self.textSuffix.setGeometry(QRect(20, 230, 261, 31)) self.textSuffix.setObjectName("textSuffix") self.textRiskf = QTextEdit(self.centralwidget) self.textRiskf.setGeometry(QRect(20, 360, 261, 31)) self.textRiskf.setObjectName("textRiskf") self.label = QLabel(self.centralwidget) self.label.setGeometry(QRect(20, 330, 261, 20)) self.label.setObjectName("label") self.label_2 = QLabel(self.centralwidget) self.label_2.setGeometry(QRect(20, 270, 281, 21)) self.label_2.setObjectName("label_2") self.label_3 = QLabel(self.centralwidget) self.label_3.setGeometry(QRect(20, 200, 261, 16)) self.label_3.setObjectName("label_3") self.label_4 = QLabel(self.centralwidget) self.label_4.setGeometry(QRect(20, 130, 261, 21)) self.label_4.setObjectName("label_4") self.label_5 = QLabel(self.centralwidget) self.label_5.setGeometry(QRect(20, 60, 261, 21)) self.label_5.setObjectName("label_5") self.startButton = QPushButton(self.centralwidget) self.startButton.setGeometry(QRect(20, 510, 111, 31)) self.startButton.setObjectName("startButton") self.label_6 = QLabel(self.centralwidget) self.label_6.setGeometry(QRect(20, 10, 261, 41)) font = QFont() font.setFamily("Times New Roman") font.setPointSize(12) font.setBold(True) font.setUnderline(True) font.setWeight(75) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.resultBrowser = QTextBrowser(self.centralwidget) self.resultBrowser.setGeometry(QRect(310, 30, 461, 501)) self.resultBrowser.setObjectName("resultBrowser") self.DateStart = QDateEdit(self.centralwidget) self.DateStart.setGeometry(QRect(20, 90, 121, 31)) self.DateStart.setMaximumDate(QDate(2050, 12, 31)) self.DateStart.setMinimumDate(QDate(1990, 12, 31)) self.DateStart.setDate(QDate(2018, 1, 1)) self.DateStart.setObjectName("DateStart") self.DateEnd = QDateEdit(self.centralwidget) self.DateEnd.setGeometry(QRect(19, 163, 121, 31)) self.DateEnd.setDateTime(QDateTime(QDate(2018, 1, 1), QTime(0, 0, 0))) self.DateEnd.setMaximumDateTime(QDateTime(QDate(2050, 12, 31), QTime(23, 59, 59))) self.DateEnd.setMinimumDate(QDate(1990, 12, 31)) self.DateEnd.setObjectName("DateEnd") self.spinBoxMode = QSpinBox(self.centralwidget) self.spinBoxMode.setGeometry(QRect(20, 290, 71, 31)) self.spinBoxMode.setMinimum(1) self.spinBoxMode.setMaximum(3) self.spinBoxMode.setObjectName("spinBoxMode") self.label_7 = QLabel(self.centralwidget) self.label_7.setGeometry(QRect(170, 300, 101, 21)) self.label_7.setObjectName("label_7") self.endButton = QPushButton(self.centralwidget) self.endButton.setGeometry(QRect(160, 510, 121, 31)) self.endButton.setObjectName("endButton") self.fileButton = QPushButton(self.centralwidget) self.fileButton.setGeometry(QRect(20, 410, 261, 31)) self.fileButton.setObjectName("fileButton") self.pathBrowser = QTextBrowser(self.centralwidget) self.pathBrowser.setGeometry(QRect(20, 450, 261, 41)) self.pathBrowser.setObjectName("pathBrowser") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setGeometry(QRect(0, 0, 800, 23)) self.menubar.setObjectName("menubar") self.menuAnalysis = QMenu(self.menubar) self.menuAnalysis.setObjectName("menuAnalysis") MainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.menubar.addAction(self.menuAnalysis.menuAction()) self.retranslateUi(MainWindow) QMetaObject.connectSlotsByName(MainWindow) #################################################### self.mythread = MyThread() self.mainthread = MyMainThread() self.fileButton.clicked.connect(lambda : self.file_path()) self.mythread.trigger.connect(self.update_text) self.mainthread.result.connect(self.update_result) self.startButton.clicked.connect(lambda : self.input_Parameters()) self.startButton.clicked.connect(lambda : self.mainthread.start()) self.startButton.clicked.connect(lambda : self.mythread.start()) self.endButton.clicked.connect(lambda : self.end_calculation()) def input_Parameters(self): self.aa = str(self.DateStart.date().toString("yyyyMMdd")) self.bb = str(self.DateEnd.date().toString("yyyyMMdd")) self.cc = str(self.textSuffix.toPlainText()) self.dd = int(self.spinBoxMode.value()) self.ee = float(self.textRiskf.toPlainText()) if self.dd==1: self.dx='p1f1' elif self.dd==2: self.dx='p0f1' elif self.dd==3: self.dx='p1f0' else: raise Exception('Running Mode is wrong') self.mainthread.parameters_in = [self.aa ,self.bb, self.cc, self.dx, self.ee, self.directory1] def file_path(self): self.directory1 = QFileDialog.getExistingDirectory(self.centralwidget,"Please choose folder","/")+'/' self.pathBrowser.append(str(self.directory1)) def update_text(self, message): self.resultBrowser.append(str(message)) def update_result(self,message): self.mythread.stop_() sleep(1) self.resultBrowser.append(str(message)) print(self.mainthread.str_result) for i in self.mainthread.str_result: print(i) self.resultBrowser.append(i) def end_calculation(self): self.mythread.stop_() self.mainthread.stop_() sleep(1) self.resultBrowser.append('\nCalculation terminated by user...') def retranslateUi(self, MainWindow): _translate = QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label.setText(_translate("MainWindow", "Please input risk free rate(0.035)")) self.label_2.setText(_translate("MainWindow", "Choose a running mode(e.g (1)p1f1/(2)p0f1")) self.label_3.setText(_translate("MainWindow", "Please input the suffix for result file")) self.label_4.setText(_translate("MainWindow", "Please input earliest date(e.g 2018-01-01)")) self.label_5.setText(_translate("MainWindow", "Please input latest date(e.g 2018-12-30)")) self.startButton.setText(_translate("MainWindow", "Start Analysis")) self.label_6.setText(_translate("MainWindow", "Barra Contribution Analysis(v_test)")) self.label_7.setText(_translate("MainWindow", " (3)p1f0")) self.endButton.setText(_translate("MainWindow", "End Process")) self.fileButton.setText(_translate("MainWindow", "Choose a folder")) self.menuAnalysis.setTitle(_translate("MainWindow", "Analysis"))