Beispiel #1
0
class SDownload(BoxLayout):

    account_id = ObjectProperty(None)
    stock_id = ObjectProperty(None)
    datatypebtn_id = ObjectProperty(None)
    startdate_id = ObjectProperty(None)
    totaldays_id = ObjectProperty(None)
    datestr_id = ObjectProperty(None)
    closebtn_id = ObjectProperty(None)
    dataType = "m"
    userConf = sutil.getDictFromFile(
        os.path.join(os.path.dirname(__file__),
                     ".." + os.sep + "conf" + os.sep + "user.ini"))

    def datatypeSelect(self, instance, atext):
        self.datatypebtn_id.text = atext
        if atext == "月線":
            self.totaldays_id.text = "全部"
            self.totaldays_id.disabled = False
            self.datestr_id.text = "月"
            self.dataType = "m"
        elif atext == "週線":
            self.totaldays_id.text = "全部"
            self.totaldays_id.disabled = False
            self.datestr_id.text = "週"
            self.dataType = "w"
        elif atext == "日線":
            self.totaldays_id.text = "90"
            self.totaldays_id.disabled = False
            self.datestr_id.text = "天"
            self.dataType = "d"
        elif atext == "tick線":
            self.totaldays_id.text = "1"
            self.totaldays_id.disabled = True
            self.datestr_id.text = "天"
            self.dataType = "0"
        else:
            self.totaldays_id.text = "5"
            self.totaldays_id.disabled = False
            self.datestr_id.text = "天"
            index = atext.find("分線")
            self.dataType = atext[0:index]

    def __init__(self, paramDict, **kwargs):
        super(SDownload, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)

        self.datatype_dropdown = DatatypeDropDown()
        self.datatypebtn_id.bind(on_release=self.datatype_dropdown.open)
        self.datatype_dropdown.bind(on_select=self.datatypeSelect)

        self.accountIDDropDown = SAccountIDDropDown()
        firstRecord = True
        accountIdList = self.app.accountIdList
        for astr in accountIdList:
            if firstRecord == True:
                firstRecord = False
                self.account_id.text = astr
            abtn = SButton(text=astr)
            abtn.size_hint_y = None
            abtn.height = 30
            abtn.bind(on_release=self.accountIDDropDown.select)
            self.accountIDDropDown.add_widget(abtn)

        self.account_id.bind(on_release=self.accountIDDropDown.open)
        self.accountIDDropDown.bind(on_select=self.accountSelect)

        self.startdate_id.bind(focus=self.onFocus)

        self.initial_data()

    def accountSelect(self, instance, atext):
        self.account_id.text = atext.text

    def onFocus(self, instance, value):
        if value:
            content = BoxLayout(size_hint=(1, 1), orientation="vertical")
            self.datePicker = SDatePicker(self.startdate_id.text)
            self.datePicker.size_hint = (1, .8)
            content.add_widget(self.datePicker)

            bottomLayout = BoxLayout(size_hint=(1, .1),
                                     orientation="horizontal")
            ensurebtn = SButton(text="確定", size_hint=(.49, .8))
            bottomLayout.add_widget(ensurebtn)
            bottomLayout.add_widget(BoxLayout(size_hint=(.02, 1)))
            closebtn = SButton(text="關閉", size_hint=(.49, .8))
            bottomLayout.add_widget(closebtn)
            content.add_widget(bottomLayout)

            self._popup = SPopup(title="日期選擇",
                                 content=content,
                                 title_font=CONSTS.FONT_NAME,
                                 size_hint=(None, None),
                                 size=(250, 330),
                                 auto_dismiss=False)
            ensurebtn.bind(on_press=self.datePickerEvent)
            closebtn.bind(on_press=self._popup.dismiss)
            self._popup.open()

    def datePickerEvent(self, instance):
        self.startdate_id.text = self.datePicker.date_text
        self._popup.dismiss()

    def initial_data(self):
        self.startdate_id.text = str(
            sdate_utils.getPrevDate(sdate_utils.getCurrentDate()))
        self.totaldays_id.text = "全部"

    def downloadData(self):
        useridTxt = self.account_id.text
        if useridTxt == "":
            self.app.showErrorView(True, CONSTS.ERR_USER_IS_SPACE)
            return

        stockidTxt = self.stock_id.text
        if stockidTxt == "":
            self.app.showErrorView(True, CONSTS.ERR_STOCKID_IS_SPACE)
            return

        if useridTxt.find("@") != -1:
            useridTxt = "1|" + useridTxt
        else:
            useridTxt = "2|" + useridTxt

        gwParam = {}
        gwParam["Host"] = self.userConf.get("DOWNLOAD_URL").strip()
        gwParam["Port"] = int(self.userConf.get("DOWNLOAD_PORT").strip())
        gwParam["User"] = useridTxt
        gwParam["Password"] = self.app.pwd
        gwParam["ProductId"] = int(self.userConf.get("PRODUCT_ID").strip())
        gwParam["UserType"] = int(self.userConf.get("USER_TYPE").strip())
        gwParam["LoginType"] = int(
            self.userConf.get("TRADE_LOGIN_TYPE").strip())
        exchange = "ZZ"
        gwParam["StockFullID"] = exchange + stockidTxt
        gwParam["DataType"] = self.dataType
        startDate = self.startdate_id.text
        if self.dataType == "m" or self.dataType == "w":
            startDate = "0"
        gwParam["StartDate"] = startDate
        totalDaysStr = self.totaldays_id.text
        if totalDaysStr == "全部":
            totalDays = "0"
        else:
            totalDays = totalDaysStr
        if self.dataType != "m" and self.dataType != "w" and self.dataType != "d":
            if int(totalDays) > 5:
                totalDays = "5"
                self.totaldays_id.text = "5"
        gwParam["DataDays"] = totalDays

        sysConfDict = self.app.confDict.get(CONSTS.SYS_CONF_DICT)

        refParam = {}
        refParam["CONSTS.S_APP"] = self.app
        refParam["TitleMsg"] = sysConfDict.get("MSG_TITLE")
        refParam["InfoMsg"] = "  資料下載中..."
        refParam["PopupSize"] = (160, 120)
        refParam["GwParam"] = gwParam
        refParam["GwFunc"] = abxtoolkit.request_rowdata
        refParam["ResultFunc"] = self._finishedDownload

        sgwPopup = SGwPopup(refParam)
        sgwPopup.processEvent()

    def _finishedDownload(self, gwResult):
        fileName = gwResult.get("FileName")
        fileLen = gwResult.get("FileLen")

        content = BoxLayout(size_hint=(1, 1), orientation="vertical")
        content.add_widget(BoxLayout(size_hint=(1, .05)))

        fileLayout = GridLayout(cols=2, spacing=2, size_hint=(1, None))
        fileLayout.bind(minimum_height=fileLayout.setter('height'))
        fileLayout.add_widget(
            SLabel(text="檔案目錄:", size_hint=(.22, None), height=30))
        fileLayout.add_widget(
            SLabel(text=download_path, size_hint=(.78, None), height=30))
        fileLayout.add_widget(
            SLabel(text="檔案名稱:", size_hint=(.22, None), height=30))
        fileLayout.add_widget(
            SLabel(text=fileName, size_hint=(.78, None), height=30))
        fileLayout.add_widget(
            SLabel(text="檔案長度:", size_hint=(.22, None), height=30))
        fileLayout.add_widget(
            SLabel(text=str(fileLen), size_hint=(.78, None), height=30))
        content.add_widget(fileLayout)

        content.add_widget(BoxLayout(size_hint=(1, .05)))

        bottomLayout = BoxLayout(size_hint=(1, .1), orientation="horizontal")
        ensurebtn = SButton(text="確定", size_hint=(1, .8))
        bottomLayout.add_widget(ensurebtn)
        content.add_widget(bottomLayout)

        self.fin_popup = Popup(title="下載完成",
                               content=content,
                               title_font=CONSTS.FONT_NAME,
                               size_hint=(None, None),
                               size=(360, 200),
                               auto_dismiss=False)
        ensurebtn.bind(on_press=self.fin_popup.dismiss)
        self.fin_popup.open()

    def showExplain(self):
        filePath = os.path.join(os.path.dirname(__file__),
                                "../conf/explain.ini")
        with open(filePath, 'r', encoding='utf-8-sig') as f:
            lineList = f.readlines()
        explainStr = ""
        for astr in lineList:
            explainStr += astr

        contentLayout = STableBoxLayout(size_hint=(1, 1),
                                        orientation="vertical")
        slview = STableScrollView(size_hint=(1, .92))
        contentLayout.add_widget(slview)
        explainLayout = STableBoxLayout(size_hint=(1, None))
        explainLayout.bind(minimum_height=explainLayout.setter('height'))
        explainLabel = SLabel(text=explainStr, size_hint=(1, None))
        explainLabel.font_name = CONSTS.FONT_NAME
        explainLabel.color = colorHex("#000000")
        explainLayout.add_widget(explainLabel)
        slview.add_widget(explainLayout)

        bottomLayout = BoxLayout(size_hint=(1, .08))
        closebtn_id = SButton(text="關閉", size_hint=(1, .8))
        bottomLayout.add_widget(closebtn_id)
        contentLayout.add_widget(bottomLayout)

        popup = SPopup(title="股票代碼說明",
                       content=contentLayout,
                       size_hint=(None, None),
                       size=(500, 400),
                       auto_dismiss=False)
        closebtn_id.bind(on_press=popup.dismiss)
        popup.title_font = CONSTS.FONT_NAME
        popup.open()
Beispiel #2
0
class STradeCost(BoxLayout):
    def __init__(self, paramDict, **kwargs):
        super(STradeCost, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)

        self.size_hint = (1, 1)
        self.orientation = "vertical"

        headLayout = STableGridLayout(cols=4,
                                      rows=1,
                                      spacing=2,
                                      size_hint=(1, None),
                                      height=30)
        headLabel = SHeadLabel(text="功能", size_hint=(.15, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="規則", size_hint=(.4, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="交易單位/契約乘數", size_hint=(.25, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="手續費+交易稅", size_hint=(.2, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        self.add_widget(headLayout)

        gapLayout = STableBoxLayout(size_hint=(1, None), height=2)
        self.add_widget(gapLayout)

        self.maxIndex = 0
        self.def_ids = {}

        slview = STableScrollView()
        slview.size_hint = (1, None)
        slview.size = (540, 350)
        self.contentLayout = STableGridLayout(cols=4,
                                              spacing=2,
                                              size_hint_y=None)
        # Make sure the height is such that there is something to scroll.
        self.contentLayout.bind(
            minimum_height=self.contentLayout.setter('height'))

        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "conf" + os.sep + "tradecost.ini")
        if not os.path.exists(filePath):
            with open(filePath, 'w'):
                pass

        alist = sutil.getListFromFile(filePath)
        for astr in alist:
            tmpList = astr.strip().split(",")
            if len(tmpList) < 3:
                continue
            self.addListRow(tmpList, False)
            self.maxIndex += 1

        self.addInsertRow(str(self.maxIndex))
        slview.add_widget(self.contentLayout)

        self.add_widget(slview)

        closeLayout = BoxLayout(size_hint=(1, None), height=36)
        self.closebtn_id = SButton(text="關閉", size_hint=(1, 1))
        closeLayout.add_widget(self.closebtn_id)
        self.add_widget(closeLayout)

    def addListRow(self, alist, aflag):
        if aflag:
            self.deleteRow(self.maxIndex)

        rowList = []
        funcLayout = SBoxLayout(size_hint=(.15, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.09, 1)))
        btn = SInfoButton(extra_info=self.maxIndex,
                          text="修",
                          size_hint=(.4, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.updateRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.02, 1)))
        btn = SInfoButton(extra_info=self.maxIndex,
                          text="刪",
                          size_hint=(.4, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.deleteRecordPopup)
        if alist[0] == "證券普通股" or alist[0] == "台指期貨":
            btn.disabled = True
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.09, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text=alist[0],
                                     size_hint=(.4, None),
                                     height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text=alist[1],
                                     size_hint=(.25, None),
                                     height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "right"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text=alist[2],
                                     size_hint=(.2, None),
                                     height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "right"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)

        self.def_ids[self.maxIndex] = rowList

    def deleteRow(self, rowIndex):
        rowList = self.def_ids.get(rowIndex)
        for obj in rowList:
            self.contentLayout.remove_widget(obj)
        self.def_ids.pop(rowIndex)
        self.saveData()

    def saveData(self):
        keylist = self.def_ids.keys()
        keylist = sorted(keylist)
        listLen = len(keylist)
        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "conf" + os.sep + "tradecost.ini")
        with open(filePath, 'w', encoding='utf-8') as f:
            rowList = None
            for i in range(0, listLen - 1):
                rowList = self.def_ids.get(keylist[i])
                astr = rowList[1].text + "," + rowList[2].text + "," + rowList[
                    3].text + "\n"
                f.write(astr)

    def addInsertRow(self, strIndex):
        rowList = []
        funcLayout = SBoxLayout(size_hint=(.15, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        btn = SButton(text="新增", size_hint=(.8, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.addRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text="", size_hint=(.4, None), height=30)
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text="", size_hint=(.25, None), height=30)
        contentLabel.halign = "right"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text="", size_hint=(.2, None), height=30)
        contentLabel.halign = "right"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)

        self.def_ids[int(strIndex)] = rowList

    def addRecordPopup(self, instance):
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict.get(key)
        refDict['mode'] = "1"
        self.add_scsLayout = SCostSetting(refDict)
        self.add_popup = SPopup(title="新增規則",
                                content=self.add_scsLayout,
                                size_hint=(None, None),
                                size=(480, 360),
                                auto_dismiss=False)
        self.add_scsLayout.ensurebtn_id.bind(on_press=self.addRecordEvent)
        self.add_scsLayout.closebtn_id.bind(on_press=self.add_popup.dismiss)
        self.add_popup.title_font = CONSTS.FONT_NAME
        self.add_popup.open()

    def addRecordEvent(self, instance):
        ruleName = self.add_scsLayout.rule_id.text
        if ruleName == None or ruleName == "":
            self.app.showErrorView(True, CONSTS.ERR_RULE_IS_SPACE)
            return
        costStr = self.add_scsLayout.cost_id.text
        if costStr == None or costStr == "":
            self.app.showErrorView(True, CONSTS.ERR_COST_IS_SPACE)
            return
        dflag = False
        try:
            float(costStr)
        except:
            dflag = True
        if dflag:
            self.app.showErrorView(True, CONSTS.ERR_COST_MUST_NUMBER)
            return
        dflag = False
        for akey in self.def_ids.keys():
            rowList = self.def_ids.get(akey)
            if ruleName == rowList[1].text:
                dflag = True
                break
        if dflag:
            self.app.showErrorView(True, CONSTS.ERR_RULE_DUPLICATED)
            return

        tradeUnit = self.add_scsLayout.tradeunit_id.text
        alist = []
        alist.append(ruleName)
        alist.append(tradeUnit)
        alist.append(costStr)
        self.addListRow(alist, True)
        self.maxIndex += 1
        self.addInsertRow(str(self.maxIndex))
        self.saveData()
        self.add_popup.dismiss()

    def updateRecordPopup(self, instance):
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict.get(key)
        refDict['mode'] = "2"
        self.update_scsLayout = SCostSetting(refDict)
        self.update_popup = SPopup(title="修改規則",
                                   content=self.update_scsLayout,
                                   size_hint=(None, None),
                                   size=(480, 360),
                                   auto_dismiss=False)
        self.update_scsLayout.ensurebtn_id.extra_info = instance.extra_info
        self.update_scsLayout.ensurebtn_id.bind(
            on_press=self.updateRecordEvent)
        self.update_scsLayout.closebtn_id.bind(
            on_press=self.update_popup.dismiss)
        self.update_popup.title_font = CONSTS.FONT_NAME
        rowList = self.def_ids.get(instance.extra_info)
        self.update_scsLayout.rule_id.text = rowList[1].text
        self.update_scsLayout.tradeunit_id.text = rowList[2].text
        self.update_scsLayout.cost_id.text = rowList[3].text
        if self.update_scsLayout.rule_id.text == "證券普通股" or self.update_scsLayout.rule_id.text == "台指期貨":
            self.update_scsLayout.tradeunit_id.disabled = True
        self.update_popup.open()

    def updateRecordEvent(self, instance):
        costStr = self.update_scsLayout.cost_id.text
        if costStr == None or costStr == "":
            self.app.showErrorView(True, CONSTS.ERR_COST_IS_SPACE)
            return
        dflag = False
        try:
            float(costStr)
        except:
            dflag = True
        if dflag:
            self.app.showErrorView(True, CONSTS.ERR_COST_MUST_NUMBER)
            return
        tradeUnit = self.update_scsLayout.tradeunit_id.text
        rowList = self.def_ids.get(instance.extra_info)
        rowList[2].text = tradeUnit
        rowList[3].text = costStr
        self.saveData()
        self.update_popup.dismiss()

    def deleteRecordPopup(self, instance):
        self.deleteConfirm = SRowConfirmLayout()
        self.del_popup = SPopup(title="刪除規則",
                                content=self.deleteConfirm,
                                size_hint=(None, None),
                                size=(240, 160),
                                auto_dismiss=False)
        self.deleteConfirm.yesbtn_id.extra_info = instance.extra_info
        self.deleteConfirm.yesbtn_id.bind(on_press=self.deleteRecordEvent)
        self.deleteConfirm.nobtn_id.bind(on_press=self.del_popup.dismiss)
        self.del_popup.title_font = CONSTS.FONT_NAME
        self.del_popup.open()

    def deleteRecordEvent(self, instance):
        self.deleteRow(instance.extra_info)
        self.del_popup.dismiss()
class SelfStkSetting(BoxLayout):
    def __init__(self, paramDict, **kwargs):
        super(SelfStkSetting, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)
        self.selfgroup_index = self.paramDict.get("SelfGroupIndex")
        self.selfgroup_name = self.paramDict.get("SelfGroupName")
        self.selfStkList = self.paramDict.get("SelfStkList")

        self.size_hint = (1, 1)
        self.orientation = "vertical"

        self.add_widget(STableBoxLayout(size_hint=(1, None), height=1))

        nameLayout = SBoxLayout(size_hint=(1, None), height=30)
        nameLayout.orientation = "horizontal"

        nameLayout.add_widget(STableBoxLayout(size_hint=(.02, 1)))

        nameLabel = SLabel(text="名稱:", size_hint=(.15, 1))
        nameLabel.color = colorHex("#000000")
        nameLayout.add_widget(nameLabel)

        self.selfgroup_name_id = STextInput(text=self.selfgroup_name,
                                            size_hint=(.65, 1))
        nameLayout.add_widget(self.selfgroup_name_id)

        nameLayout.add_widget(STableBoxLayout(size_hint=(.23, 1)))

        self.add_widget(nameLayout)

        self.add_widget(STableBoxLayout(size_hint=(1, None), height=1))

        headLayout = STableGridLayout(cols=3,
                                      rows=1,
                                      spacing=2,
                                      size_hint=(1, None),
                                      height=30)
        headLabel = SHeadLabel(text="功能", size_hint=(.15, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="代碼", size_hint=(.2, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="名稱", size_hint=(.65, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        self.add_widget(headLayout)

        self.add_widget(STableBoxLayout(size_hint=(1, None), height=2))

        self.def_ids = {}

        slview = STableScrollView()
        slview.size_hint = (1, None)
        slview.size = (360, 320)
        self.contentLayout = STableGridLayout(cols=3,
                                              spacing=2,
                                              size_hint_y=None)
        # Make sure the height is such that there is something to scroll.
        self.contentLayout.bind(
            minimum_height=self.contentLayout.setter('height'))

        tmpList = None
        stkName = None
        for stkId in self.selfStkList:
            tmpList = []
            tmpList.append(stkId)
            stkName = self.app.stkNameDict.get(stkId)
            if stkName == None:
                tmpList.append("")
            else:
                tmpList.append(stkName)
            self.addListRow(tmpList)

        self.addInsertRow()
        slview.add_widget(self.contentLayout)

        self.add_widget(slview)

        bottomLayout = BoxLayout(size_hint=(1, None), height=30)
        self.ensurebtn_id = SButton(text="確定", size_hint=(.49, 1))
        bottomLayout.add_widget(self.ensurebtn_id)
        bottomLayout.add_widget(BoxLayout(size_hint=(.02, 1)))
        self.cancelbtn_id = SButton(text="取消", size_hint=(.49, 1))
        bottomLayout.add_widget(self.cancelbtn_id)
        self.add_widget(bottomLayout)

    def addListRow(self, alist):

        rowList = []
        funcLayout = SBoxLayout(size_hint=(.15, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        btn = SInfoButton(extra_info=alist[0], text="刪", size_hint=(.8, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.deleteRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text=alist[0][2:],
                                     size_hint=(.2, None),
                                     height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "center"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text=alist[1],
                                     size_hint=(.65, None),
                                     height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)

        self.def_ids[alist[0]] = rowList

    def deleteRow(self, rowId):
        rowList = self.def_ids.get(rowId)
        for obj in rowList:
            self.contentLayout.remove_widget(obj)
        self.def_ids.pop(rowId)
        if rowId in self.selfStkList:
            self.selfStkList.remove(rowId)

    def saveData(self):
        stkListStr = ""
        for stkId in self.selfStkList:
            stkListStr += stkId + "|"
        if len(stkListStr) != 0:
            stkListStr = stkListStr[0:-1]

        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "conf" + os.sep + "self_stkquote.ini")
        alist = sutil.getListFromFile(filePath)
        with open(filePath, 'w', encoding='utf-8') as f:
            for tmpStr in alist:
                aList = tmpStr.split(",")
                if int(aList[0]) == self.selfgroup_index:
                    astr = str(
                        self.selfgroup_index
                    ) + "," + self.selfgroup_name_id.text + "," + stkListStr + "\n"
                else:
                    astr = tmpStr + "\n"
                f.write(astr)

    def addInsertRow(self):
        rowList = []
        funcLayout = SBoxLayout(size_hint=(.15, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        btn = SInfoButton(extra_info=INSERT_ROW_ID,
                          text="新增",
                          size_hint=(.8, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.addRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text="", size_hint=(.2, None), height=30)
        contentLabel.halign = "center"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text="", size_hint=(.65, None), height=30)
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)

        self.def_ids[INSERT_ROW_ID] = rowList

    def addRecordPopup(self, instance):
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict.get(key)
        self.add_scsLayout = StkQuery(refDict)
        self.add_popup = SPopup(title="新增自選股票",
                                content=self.add_scsLayout,
                                size_hint=(None, None),
                                size=(480, 360),
                                auto_dismiss=False)
        self.add_scsLayout.ensureBtn_id.bind(on_press=self.addRecordEvent)
        self.add_scsLayout.cancelBtn_id.bind(on_press=self.add_popup.dismiss)
        self.add_popup.title_font = CONSTS.FONT_NAME
        self.add_popup.open()

    def addRecordEvent(self, instance):
        self.add_scsLayout.doSelectStk()

        if len(self.add_scsLayout.selectIdNameList) == 0:
            return

        duplicatedIds = []
        for aList in self.add_scsLayout.selectIdNameList:
            if aList[0] in self.selfStkList:
                duplicatedIds.append(aList[0][2:])
        if len(duplicatedIds) != 0:
            self.app.showErrorView(True, CONSTS.ERR_STKID_DUPLICATED,
                                   duplicatedIds)
            return

        self.deleteRow(INSERT_ROW_ID)

        for aList in self.add_scsLayout.selectIdNameList:
            self.addListRow(aList)
            self.selfStkList.append(aList[0])

        self.addInsertRow()

        self.add_popup.dismiss()

    def deleteRecordPopup(self, instance):
        self.deleteConfirm = SRowConfirmLayout()
        self.del_popup = SPopup(title="刪除自選股票",
                                content=self.deleteConfirm,
                                size_hint=(None, None),
                                size=(240, 160),
                                auto_dismiss=False)
        self.deleteConfirm.yesbtn_id.extra_info = instance.extra_info
        self.deleteConfirm.yesbtn_id.bind(on_press=self.deleteRecordEvent)
        self.deleteConfirm.nobtn_id.bind(on_press=self.del_popup.dismiss)
        self.del_popup.title_font = CONSTS.FONT_NAME
        self.del_popup.open()

    def deleteRecordEvent(self, instance):
        self.deleteRow(instance.extra_info)
        self.del_popup.dismiss()
Beispiel #4
0
class SStrategy(BoxLayout):
        
    def __init__(self, paramDict, **kwargs):
        super(SStrategy, self).__init__(**kwargs)
        
        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)        

        self.size_hint = (1, 1)
        self.orientation = "vertical"

        headLayout = STableGridLayout(cols=3, rows=1, spacing=2, size_hint=(1, None), height=30)
        headLabel = SHeadLabel(text="功能", size_hint=(.15, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="策略名稱", size_hint=(.6, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        headLabel = SHeadLabel(text="檔案名稱", size_hint=(.25, 1))
        headLabel.halign: 'center'
        headLabel.valign: 'middle'
        headLayout.add_widget(headLabel)
        self.add_widget(headLayout)
        
        gapLayout = STableBoxLayout(size_hint=(1, None), height=2)
        self.add_widget(gapLayout)
        
        self.maxIndex = 0
        self.def_ids = {}
        
        slview = STableScrollView()
        slview.size_hint = (1, None)
        slview.size = (540, 350)
        self.contentLayout = STableGridLayout(cols=3, spacing=2, size_hint_y=None)
        # Make sure the height is such that there is something to scroll.
        self.contentLayout.bind(minimum_height=self.contentLayout.setter('height'))
        
        filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "strategy.ini")
        if not os.path.exists(filePath):
            with open(filePath, 'w'): pass        
            
        alist = sutil.getListFromFile(filePath)
        for astr in alist:
            tmpList = astr.strip().split(",")
            if len(tmpList) < 2:
                continue
            self.addListRow(tmpList, False)
            self.maxIndex += 1            

        self.addInsertRow(str(self.maxIndex))
        slview.add_widget(self.contentLayout)
        
        self.add_widget(slview)
        
        closeLayout = BoxLayout(size_hint=(1, None), height=36)
        self.closebtn_id = SButton(text="關閉", size_hint=(1, 1))
        closeLayout.add_widget(self.closebtn_id)
        self.add_widget(closeLayout)

    def addListRow(self, alist, aflag):
        if aflag:
            self.deleteRow(self.maxIndex)
        
        rowList = []
        funcLayout = SBoxLayout(size_hint=(.25, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.06, 1)))
        btn = SInfoButton(extra_info=self.maxIndex, text="修", size_hint=(.14, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.updateRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.02, 1)))
        btn = SInfoButton(extra_info=self.maxIndex, text="刪", size_hint=(.14, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.deleteRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.02, 1)))        
        btn = SInfoButton(extra_info=self.maxIndex, text="編輯策略", size_hint=(.56, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.editContent)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.06, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text=alist[0], size_hint=(.5, None), height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text=alist[1], size_hint=(.25, None), height=30)
        contentLabel.color = colorHex("#000000")
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        
        self.def_ids[self.maxIndex] = rowList

    def deleteRow(self, rowIndex):
        rowList = self.def_ids.get(rowIndex)
        for obj in rowList:
            self.contentLayout.remove_widget(obj)
        self.def_ids.pop(rowIndex)
        if rowList[2].text != "":
            filePath = os.path.abspath(os.path.join(save_dir, rowList[2].text))
            if os.path.exists(filePath):
                os.remove(filePath)
        self.saveData()

    def saveData(self):
        keylist = self.def_ids.keys()
        keylist = sorted(keylist)
        listLen = len(keylist)
        filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "strategy.ini")
        with open(filePath, 'w', encoding = 'utf-8') as f:
            rowList = None
            for i in range(0, listLen - 1):
                rowList = self.def_ids.get(keylist[i])
                astr = rowList[1].text + "," + rowList[2].text + "\n"
                f.write(astr)

    def addInsertRow(self, strIndex):
        rowList = []
        funcLayout = SBoxLayout(size_hint=(.25, None), height=30)
        funcLayout.orientation = "horizontal"
        funcLayout.padding = (1, 1, 1, 1)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        btn = SButton(text="新增", size_hint=(.8, 1))
        btn.halign = "center"
        btn.valign = "middle"
        btn.bind(on_release=self.addRecordPopup)
        funcLayout.add_widget(btn)
        funcLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        rowList.append(funcLayout)
        self.contentLayout.add_widget(funcLayout)
        contentLabel = SContentLabel(text="", size_hint=(.5, None), height=30)
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        contentLabel = SContentLabel(text="", size_hint=(.25, None), height=30)
        contentLabel.halign = "left"
        contentLabel.valign = "middle"
        rowList.append(contentLabel)
        self.contentLayout.add_widget(contentLabel)
        
        self.def_ids[int(strIndex)] = rowList

    def addRecordPopup(self, instance):
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict.get(key)
        refDict['mode'] = "1"
        self.add_scsLayout = SStrategySetting(refDict)
        self.add_popup = SPopup(title="新增策略", content=self.add_scsLayout,
                size_hint=(None, None), size=(560, 440), auto_dismiss=False)
        self.add_scsLayout.ensurebtn_id.bind(on_press=self.addRecordEvent)
        self.add_scsLayout.closebtn_id.bind(on_press=self.add_popup.dismiss)
        self.add_popup.title_font = CONSTS.FONT_NAME
        self.add_popup.open()

    def addRecordEvent(self, instance):
        strategyName = self.add_scsLayout.strategy_id.text
        if strategyName == None or strategyName == "":
            self.app.showErrorView(True, CONSTS.ERR_STRATEGY_IS_SPACE)
            return
        
        dflag = False
        for akey in self.def_ids.keys():
            rowList = self.def_ids.get(akey)
            if strategyName == rowList[1].text:
                dflag = True
                break
        if dflag:
            self.app.showErrorView(True, CONSTS.ERR_STRATEGY_DUPLICATED)
            return
        
        fileName = self.add_scsLayout.filename_id.text
        alist = []
        alist.append(strategyName)
        alist.append(fileName)
        self.addListRow(alist, True)
        self.maxIndex += 1
        self.addInsertRow(str(self.maxIndex))
        self.saveData()
        self.add_popup.dismiss()
        self.filePathTmp = os.path.abspath(os.path.join(save_dir, fileName))
        open(self.filePathTmp, 'a').close()
        threading.Thread(target=self.openFile).start()

    def openFile(self):
        os.system(self.filePathTmp)

    def updateRecordPopup(self, instance):
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict.get(key)
        refDict['mode'] = "2"
        self.update_scsLayout = SStrategySetting(refDict)
        self.update_popup = SPopup(title="修改策略", content=self.update_scsLayout,
                size_hint=(None, None), size=(560, 440), auto_dismiss=False)
        self.update_scsLayout.ensurebtn_id.extra_info = instance.extra_info
        self.update_scsLayout.ensurebtn_id.bind(on_press=self.updateRecordEvent)
        self.update_scsLayout.closebtn_id.bind(on_press=self.update_popup.dismiss)
        self.update_popup.title_font = CONSTS.FONT_NAME
        rowList = self.def_ids.get(instance.extra_info)
        self.update_scsLayout.strategy_id.text = rowList[1].text
        self.update_scsLayout.filename_id.text = rowList[2].text
        self.update_popup.open()

    def updateRecordEvent(self, instance):
        rowIndex = instance.extra_info
        strategyName = self.update_scsLayout.strategy_id.text
        if strategyName == None or strategyName == "":
            self.app.showErrorView(True, CONSTS.ERR_STRATEGY_IS_SPACE)
            return
        fileName = self.update_scsLayout.filename_id.text
        dflag = False
        for akey in self.def_ids.keys():
            if akey == rowIndex:
                continue
            rowList = self.def_ids.get(akey)
            if strategyName == rowList[1].text and fileName == rowList[2].text:
                dflag = True
                break
        if dflag:
            self.app.showErrorView(True, CONSTS.ERR_STRATEGY_DUPLICATED)
            return
        rowList = self.def_ids.get(rowIndex)
        rowList[1].text = strategyName
        self.saveData()
        self.update_popup.dismiss()
        self.filePathTmp = os.path.abspath(os.path.join(save_dir, fileName))
        threading.Thread(target=self.openFile).start()        

    def deleteRecordPopup(self, instance):
        self.deleteConfirm = SRowConfirmLayout()
        self.del_popup = SPopup(title="刪除策略", content=self.deleteConfirm,
                size_hint=(None, None), size=(240, 160), auto_dismiss=False)
        self.deleteConfirm.yesbtn_id.extra_info = instance.extra_info
        self.deleteConfirm.yesbtn_id.bind(on_press=self.deleteRecordEvent)
        self.deleteConfirm.nobtn_id.bind(on_press=self.del_popup.dismiss)
        self.del_popup.title_font = CONSTS.FONT_NAME
        self.del_popup.open()

    def deleteRecordEvent(self, instance):
        self.deleteRow(instance.extra_info)
        self.del_popup.dismiss()
    
    def editContent(self, instance):
        rowList = self.def_ids.get(int(instance.extra_info))
        filePath = os.path.join(save_dir, rowList[2].text)
        os.system(os.path.abspath(filePath))
Beispiel #5
0
class StkQuote(BoxLayout):

    head_layout = ObjectProperty(None)
    body_layout = ObjectProperty(None)
    selfStkList = ObjectProperty(None)
    subscribeList = ObjectProperty(None)
        
    def __init__(self, paramDict, **kwargs):
        super(StkQuote, self).__init__(**kwargs)
        
        self.lock = threading.RLock()

        self.size_hint = (1, 1)
        self.orientation = "vertical"

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)
        self.dispIdName = self.paramDict.get("dispIdName", True)
        self.headDict = self.paramDict.get("headDict")
        self.headIdList = []
        self.headIdList.append("id")
        self.headIdList.append("name")
        
        for aKey in self.headDict.keys():
            if aKey == "id" or aKey == "name":
                continue
            else:
                self.headIdList.append(aKey)
        
        self.fieldIdList = [] #記錄資料的欄位列表(不包含id及name欄位)
        self.dispIdList = [] #記錄顯示的欄位列表
        """
        if self.dispIdName == True:
            self.dispIdList內容為 ['id','name','price','vol', ...]
        else:
            self.dispIdList內容為 ['id'(or 'name'),'price','vol', ...]
        """
        self.fieldMapping = {} #記錄資料欄位與顯示欄位的對應,''代表畫面不顯示此欄位
        """
        if self.dispIdName == True:
            {'id':'0', 'name':'1', 'price':'2', 'vol':'3', ...,}
        else:
            {'name':'0'(or 'id':'0'), 'price':'1', 'vol':'2', ...,}
        """
        self.dispFieldMapping = {} #記錄顯示欄位與資料欄位的對應
        """
        if self.dispIdName == True:
            {'0':'id', '1':'name', '2':'price', '3':'vol', ...}
        else:
            {'0':'name'(or '0':'id'), '1':'price', '2':'vol', ...}
        """
        # 1001-Begin: 以下將欄位訊息儲存至相關的變數中
        shiftIdx = 1
        self.fieldMapping["name"] = "0"
        if self.dispIdName == True:
            self.fieldMapping["id"] = "0"
            self.dispFieldMapping["0"] = "id"
            self.dispIdList.append("id")
            self.fieldMapping["name"] = "1"
            self.dispFieldMapping["1"] = "name"
            self.dispIdList.append("name")
            shiftIdx = 0
        else:
            self.dispIdList.append("name")
            self.fieldMapping["id"] = ""
            self.dispFieldMapping["0"] = "name"
        for idx in range(2, len(self.headIdList)):
            self.fieldIdList.append(self.headIdList[idx])
            if (idx - shiftIdx) >= COLUMN_NUM:
                self.fieldMapping[self.headIdList[idx]] = ""
            else:
                self.fieldMapping[self.headIdList[idx]] = str(idx - shiftIdx)
                self.dispFieldMapping[str(idx - shiftIdx)] = self.headIdList[idx]
                self.dispIdList.append(self.headIdList[idx])

        self.headButtonList = [] #記錄標題之Button List
        self.quoteBaseDict = {} #記錄股票基本資料之字典
        self.quoteDataDict = {} #記錄所有報價資料之字典
        """self.quoteDataDict資料格式如下所示:
           stkid: {'id': [stkId,fg_color,bg_color],'name': [stkName,fg_color,bg_color],'price': [priceValue,fg_color,bg_color], ...}
           example: 'T11101': {'id':['T11101','#000000','#FFFFFF'],'name':['台泥','#000000','#FFFFFF'],'price':[10.0,'#000000','#FFFFFF']}
        """
        self.dispDict = {} #記錄顯示物件的字典
        """self.dispDict資料格式如下所示:
        {stkid:{'0':Kivy Object, '1': Kivy Object, ....},stkid:{'0':Kivy Object, '1': Kivy Object, ....}}
        """

        headNum = len(self.dispFieldMapping) #取得畫面顯示的欄位數
        self.headLayout = STableGridLayout(cols=headNum, rows=1, spacing=2, size_hint=(1, 1))
        #1000-Start: 計算欄位寬度的size_hint
        if headNum < COLUMN_NUM: #如果欄位數比預設欄位數少
            self.idWidth_hint = 1.0 / headNum
            self.otherWidth_hint = self.idWidth_hint
        else:
            self.idWidth_hint = 0.1
            addWidth_hint = 0.1
            addField = 1
            if self.dispIdName == True:
                addWidth_hint += 0.1
                addField += 1
            self.otherWidth_hint = (1.0 - addWidth_hint) / (headNum - addField)
        #1000-End.
        for colIndexStr in self.dispFieldMapping.keys():
            headId = self.dispFieldMapping.get(colIndexStr)
            field = self.headDict.get(headId)
            if headId == "id" or headId == "name":
                headButton = SHeadSortedButton(headText = field, headIndex = headId, text = field, size_hint = (self.idWidth_hint, 1))
            else:
                headButton = SHeadSortedButton(headText = field, headIndex = headId, text = field, size_hint = (self.otherWidth_hint, 1))
            self.headLayout.add_widget(headButton)
            self.headButtonList.append(headButton)
        self.head_layout.add_widget(self.headLayout)

        self.contentLayout = STableGridLayout(cols=headNum, spacing=2, size_hint_y=None)
        # Make sure the height is such that there is something to scroll.
        self.contentLayout.bind(minimum_height=self.contentLayout.setter('height'))
        
        self.body_layout.add_widget(self.contentLayout)

    def setStkList(self, selfStkList):
        self.selfStkList = selfStkList
    
    def setSubscribeList(self, subscribeList):
        self.subscribeList = subscribeList

    def setGroupName(self, groupName):
        self.groupName = groupName

    def _getDefaultDict(self):
        aDict = {}
        for headId in self.headIdList:
            aDict[headId] = ['', DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
        return aDict 

    @synchronized_with_attr("lock")
    def _getDefaultRowDict(self, aDict):
        dispObjDict = {}
        for colIndexStr in self.dispFieldMapping.keys():                     
            headId = self.dispFieldMapping.get(colIndexStr)
            fieldList = aDict.get(headId)
            contentObj = None
            if headId == "id":
                contentObj = SButton(size_hint = (self.idWidth_hint, None), height=30)
                contentObj.text = fieldList[0]
                contentObj.halign = "center"
                contentObj.bind(on_press=self._id_press)
            elif headId == "name":
                contentObj = SButton(size_hint = (self.idWidth_hint, None), height=30)
                contentObj.text = fieldList[0]
                contentObj.halign = "center"
                contentObj.bind(on_press=self._name_press)                
            else:
                contentObj = SContentLabel(size_hint = (self.otherWidth_hint, None), height=30)
                contentObj.text = fieldList[0]
                contentObj.color = colorHex(fieldList[1])
                if headId == "TT":
                    contentObj.halign = "center"
                else:
                    contentObj.halign = "right"
            dispObjDict[colIndexStr] = contentObj
        return dispObjDict

    def _openOptionPopup(self):
        content = BoxLayout(size_hint=(1, 1), orientation="vertical")
        
        strendBtn = SButton(text="走勢圖", size_hint=(1, None), height=30)
        strendBtn.bind(on_press=self._openStrendChart)
        content.add_widget(strendBtn)
        
        content.add_widget(BoxLayout(size_hint=(1, None), height=1))
        
        stechBtn = SButton(text="技術分析", size_hint=(1, None), height=30)
        stechBtn.bind(on_press=self._openStechChart)
        content.add_widget(stechBtn)
        
        content.add_widget(BoxLayout(size_hint=(1, None), height=1))

        closeBtn = SButton(text="關閉", size_hint=(1, None), height=30)
        content.add_widget(closeBtn)

        titleName = self.oneStkDict.get("id") + " " + self.oneStkDict.get("name")
        self.option_popup = SPopup(title=titleName, content=content, title_font=CONSTS.FONT_NAME,
                        size_hint=(None, None), size=(240, 152), auto_dismiss=False)
        closeBtn.bind(on_press=self.option_popup.dismiss)
        self.option_popup.open()

    def _id_press(self, instance):
        self.oneStkDict = {}
        currIdx = -1
        for aKey in self.quoteBaseDict.keys():
            currIdx += 1
            if instance.text == aKey[2:]:
                self.oneStkDict = self.quoteBaseDict.get(aKey)
                break
        
        self.currIndex = currIdx
        self._openOptionPopup()

    def _name_press(self, instance):
        self.oneStkDict = {}
        currIdx = -1
        for aKey in self.quoteBaseDict.keys():
            currIdx += 1
            aDict = self.quoteBaseDict.get(aKey)
            if instance.text == aDict.get("name"):
                self.oneStkDict = aDict
                break

        self.currIndex = currIdx
        self._openOptionPopup()
    
    def _openStrendChart(self, instance):
        self.option_popup.dismiss()
        
        refParam = {}
        refParam[CONSTS.S_APP] = self.app
        refParam["ChartType"] = "1"
        refParam["GroupName"] = self.groupName
        refParam["SelfStkList"] = self.selfStkList
        refParam["SubscribeList"] = self.subscribeList
        refParam["QuoteBaseDict"] = self.quoteBaseDict
        refParam["OneStkDict"] = self.oneStkDict
      
        self.stcLayout = StkGroupView(refParam)
        self.strend_popup = SPopup(title="走勢圖&技術分析", content=self.stcLayout,
            size_hint=(None, None), size=(720, 540), auto_dismiss=False)
        self.stcLayout.closebtn_id.bind(on_press=self._strend_popup_dismiss)
        self.strend_popup.title_font = CONSTS.FONT_NAME
        self.strend_popup.open()

    def _strend_popup_dismiss(self, instance):
        self.strend_popup.dismiss()
        self.stcLayout.removeListener()    

    def _openStechChart(self, instance):
        self.option_popup.dismiss()
        
        refParam = {}
        refParam[CONSTS.S_APP] = self.app
        refParam["ChartType"] = "2"
        refParam["GroupName"] = self.groupName
        refParam["SelfStkList"] = self.selfStkList
        refParam["SubscribeList"] = self.subscribeList
        refParam["QuoteBaseDict"] = self.quoteBaseDict
        refParam["OneStkDict"] = self.oneStkDict

        self.sttLayout = StkGroupView(refParam)
        self.stech_popup = SPopup(title="走勢圖&技術分析", content=self.sttLayout,
            size_hint=(None, None), size=(720, 540), auto_dismiss=False)
        self.sttLayout.closebtn_id.bind(on_press=self._stech_popup_dismiss)
        self.stech_popup.title_font = CONSTS.FONT_NAME
        self.stech_popup.open()
    
    def _stech_popup_dismiss(self, instance):
        self.stech_popup.dismiss()
        self.sttLayout.removeListener()    

    @synchronized_with_attr("lock")
    def updateBaseQuote(self, baseList):
        for aDict in baseList:
            stkId = aDict.get("id")
            if stkId == None:
                continue
            else:
                existDict = self.quoteBaseDict.get(stkId)
                if existDict == None: #若無報價基本資料,創建一新的字典
                    existDict = {}
                tmpId = None
                for headId in aDict.keys():
                    existDict[headId] = aDict.get(headId)               
                self.quoteBaseDict[stkId] = existDict
        
    @synchronized_with_attr("lock")
    def updateQuote(self, quoteList):
        """
        
        """
        if quoteList == None or len(quoteList) == 0:
            return
        #5001-Start: 若無id欄位,則不添加至報價列表;若資料已存在,則更新資料
        for aDict in quoteList:
            id_dataList = aDict.get("id")
            if id_dataList == None:
                continue
            else:
                existFlag = True
                stkId = id_dataList[0]
                existDict = self.quoteDataDict.get(stkId)
                if existDict == None: #若無報價資料,初始化一筆報價資料
                    existFlag = False
                    existDict = self._getDefaultDict() # 初始化報價資料
                dispObjDict = None
                if existFlag == True: #若已存在報價資料,則直接取得畫面上顯示之物件
                    dispObjDict = self.dispDict.get(stkId)
                else: #若無報價資料,則初始化一筆畫面上顯示之物件
                    dispObjDict = self._getDefaultRowDict(existDict)
                    self.dispDict[stkId] = dispObjDict
                    for rowNum in dispObjDict.keys():
                        self.contentLayout.add_widget(dispObjDict.get(rowNum))
                tmpId = None
                for headId in aDict.keys():
                    tmpHeadId = existDict.get(headId)
                    if tmpHeadId != None:
                        existDict[headId] = aDict.get(headId)
                        fieldIdx = self.fieldMapping.get(headId) #取得欄位對應之顯示欄位的index
                        if fieldIdx != None and fieldIdx != "":
                            kvObj = dispObjDict.get(fieldIdx)
                            valueList = aDict.get(headId)
                            if headId == "id":
                                kvObj.text = valueList[0][2:]
                            else:
                                kvObj.text = valueList[0]
                            if headId != "id" and headId != "name":
                                kvObj.color = colorHex(valueList[1])
                            time.sleep(0.0001) # 2020/10/28 調整,因應欄位顯示空白問題
                self.quoteDataDict[stkId] = existDict
        #5001-End.

    @synchronized_with_attr("lock")
    def clearQuote(self):
        if self.contentLayout != None:
            self.contentLayout.clear_widgets()
        self.quoteBaseDict.clear()
        self.quoteDataDict.clear()
        self.dispDict.clear()

    @synchronized_with_attr("lock")
    def resetFieldsSeq(self, fieldIdList):
        self.fieldIdList = fieldIdList
        headIdIndex = -1
        for aObj in self.headButtonList:
            if aObj.headIndex == "id" or aObj.headIndex == "name":
                continue
            headIdIndex += 1
            headId = self.fieldIdList[headIdIndex]
            aObj.headIndex = headId
            aObj.text = self.headDict.get(headId)

        self._shiftDispField()        

    @synchronized_with_attr("lock")
    def nextField(self):
        removeId = self.fieldIdList.pop(0)
        self.fieldIdList.append(removeId)
        headIdIndex = -1
        for aObj in self.headButtonList:
            if aObj.headIndex == "id" or aObj.headIndex == "name":
                continue
            headIdIndex += 1
            headId = self.fieldIdList[headIdIndex]
            aObj.headIndex = headId
            aObj.text = self.headDict.get(headId)

        self._shiftDispField()
    
    @synchronized_with_attr("lock")
    def previousField(self):
        removeId = self.fieldIdList.pop(-1)
        self.fieldIdList.insert(0, removeId)
        headIdIndex = -1
        for aObj in self.headButtonList:
            if aObj.headIndex == "id" or aObj.headIndex == "name":
                continue
            headIdIndex += 1
            headId = self.fieldIdList[headIdIndex]
            aObj.headIndex = headId
            aObj.text = self.headDict.get(headId)
        
        self._shiftDispField()  

    def _shiftDispField(self):
        for headId in self.fieldMapping.keys(): #將id及name以外的欄位,重新設置欄位對應
            if headId == "id" or headId == "name":
                continue
            self.fieldMapping[headId] = ""

        headIdIndex = -1
        for colIndexStr in self.dispFieldMapping.keys():
            headId = self.dispFieldMapping.get(colIndexStr)
            if headId == "id" or headId == "name":
                continue
            headIdIndex += 1
            headId = self.fieldIdList[headIdIndex]
            self.dispFieldMapping[colIndexStr] = headId
            self.fieldMapping[headId] = colIndexStr
        for stkId in self.dispDict.keys():
            dispObjDict = self.dispDict.get(stkId)
            aQuoteDict = self.quoteDataDict.get(stkId)
            for rowNum in dispObjDict.keys():
                kvObj = dispObjDict.get(rowNum)
                headId = self.dispFieldMapping.get(rowNum)
                aDataList = aQuoteDict.get(headId)
                if headId == "id":
                    kvObj.text = aDataList[0][2:]
                else:
                    kvObj.text = aDataList[0]                
                kvObj.color = colorHex(aDataList[1])
                if headId == "id" or headId == "name" or headId == "TT":
                    kvObj.halign = "center"
                else:
                    kvObj.halign = "right"
class SelfStkQuote(BoxLayout):

    body_layout = ObjectProperty(None)
    content_layout = ObjectProperty(None)
    selfgroup_id = ObjectProperty(None)
    page_id = ObjectProperty(None)
    totalpage_id = ObjectProperty(None)
    prepage_id = ObjectProperty(None)
    nextpage_id = ObjectProperty(None)
    fieldRight_id = ObjectProperty(None)
    fieldLeft_id = ObjectProperty(None)
    selfgroup_index = 0
    selfStkList = []

    def __init__(self, paramDict, **kwargs):
        super(SelfStkQuote, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)

        self.quoteDataDict = {}
        self.selfDict = {}
        self.selfDropDown = SSelfDropDown()
        self.dropDownDict = {}
        firstRecord = True
        selfGroupList = None
        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "conf" + os.sep + "self_stkquote.ini")
        alist = sutil.getListFromFile(filePath)
        for astr in alist:
            selfGroupList = astr.strip().split(",")
            if len(selfGroupList) < 3:
                continue
            if firstRecord:
                firstRecord = False
                self.selfgroup_id.text = selfGroupList[1]
                self.selfgroup_index = int(selfGroupList[0])
            self.selfDict[int(selfGroupList[0])] = selfGroupList
            abtn = SInfoButton(extra_info=int(selfGroupList[0]),
                               text=selfGroupList[1])
            abtn.size_hint_y = None
            abtn.height = 30
            abtn.bind(on_release=self.selfDropDown.select)
            self.selfDropDown.add_widget(abtn)
            self.dropDownDict[str(abtn.extra_info)] = abtn

        self.selfgroup_id.bind(on_release=self.selfDropDown.open)
        self.selfDropDown.bind(on_select=self.selfSelect)

        self.stkidList = []
        self.num_per_page = NUM_PER_PAGE
        self.page_num = 1
        self.max_page_num = 1

        self.page_id.bind(on_text_validate=self._on_page_id_enter)

        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "conf" + os.sep + "stkfields_setting.ini")
        alist = sutil.getListFromFile(filePath)
        headDefineDict = {}
        for astr in alist:
            astrList = astr.strip().split(",")
            if len(astrList) < 2:
                continue
            headDefineDict[astrList[0]] = astrList[1]
        headDict = {}
        headDict["id"] = headDefineDict.get("id")  #SID
        headDict["name"] = headDefineDict.get("name")  #SNT
        seqStr = headDefineDict.get("_SEQ_")
        seqStrList = seqStr.split("|")
        for headId in seqStrList:
            headDict[headId] = headDefineDict.get(headId)
        self.stkquote = StkQuote({
            CONSTS.S_APP: self.app,
            'headDict': headDict,
            'dispIdName': True
        })

        self.body_layout.remove_widget(self.content_layout)
        self.content_layout = self.stkquote
        self.content_layout.size_hint = (1, 1)
        self.body_layout.add_widget(self.content_layout)

        Clock.schedule_once(self.doQuoteStart, .5)  #此段用意為讓畫面先顯示出來,再做後續的動作

    def selfSelect(self, instance, atext):
        self.selfgroup_id.text = atext.text
        self.selfgroup_index = atext.extra_info
        self.stkquote.clearQuote()  #變更自選組合,先清掉之前的畫面
        selfStkListStr = self.selfDict.get(self.selfgroup_index)[2]  #取得新的自選組合
        if selfStkListStr == "" or len(selfStkListStr) == 0:
            self.selfStkList = []
        else:
            self.selfStkList = selfStkListStr.split("|")

        self._calcPageInfo()
        self.subscribeQuote()  #重新訂閱股票

    def _stkSetting(self):
        if len(self.app.stkNameDict) == 0:
            self._doQueryStktbl()
        else:
            refParam = {}
            refParam[CONSTS.S_APP] = self.app
            refParam["SelfGroupIndex"] = self.selfgroup_index
            refParam["SelfGroupName"] = self.selfgroup_id.text
            refParam["SelfStkList"] = list(self.selfStkList)
            stcLayout = SelfStkSetting(refParam)
            self.stcLayout = stcLayout
            self.self_setting_popup = SPopup(title="自選設定",
                                             content=stcLayout,
                                             size_hint=(None, None),
                                             size=(360, 480),
                                             auto_dismiss=False)
            stcLayout.ensurebtn_id.bind(on_press=self._changeGroup)
            stcLayout.cancelbtn_id.bind(
                on_press=self._self_setting_popup_dismiss)
            self.self_setting_popup.title_font = CONSTS.FONT_NAME
            self.self_setting_popup.open()

    def _fieldsSetting(self):
        refParam = {}
        refParam[CONSTS.S_APP] = self.app
        sfsLayout = SFieldSetting(refParam)
        self.sfsLayout = sfsLayout
        self.self_fieldsetting_popup = SPopup(title="欄位排序",
                                              content=sfsLayout,
                                              size_hint=(None, None),
                                              size=(300, 480),
                                              auto_dismiss=False)
        sfsLayout.ensurebtn_id.bind(on_press=self._changeFields)
        sfsLayout.closebtn_id.bind(
            on_press=self.self_fieldsetting_popup.dismiss)
        self.self_fieldsetting_popup.title_font = CONSTS.FONT_NAME
        self.self_fieldsetting_popup.open()

    def _doQueryStktbl(self):

        gwParam = {}
        gwParam['PinyinType'] = "1"
        gwParam['LanguageID'] = "T"
        gwParam['ExchangeID'] = "TW"

        sysConfDict = self.app.confDict.get(CONSTS.SYS_CONF_DICT)

        refParam = {}
        refParam["CONSTS.S_APP"] = self.app
        refParam["TitleMsg"] = sysConfDict.get("MSG_TITLE")
        refParam["InfoMsg"] = "  股名檔下載中..."
        refParam["PopupSize"] = (160, 120)
        refParam["GwParam"] = gwParam
        refParam["GwFunc"] = abxtoolkit.query_stktbl1
        refParam["ResultFunc"] = self._finishedQueryStktbl

        sgwPopup = SGwPopup(refParam)
        sgwPopup.processEvent()

    def _finishedQueryStktbl(self, gwResult):
        filePath = os.path.join(
            os.path.dirname(__file__),
            ".." + os.sep + "rowdata" + os.sep + "stktbl1TTW.dat")
        alist = sutil.getListFromFile(filePath)
        alist.pop(0)
        tmpList = None
        for astr in alist:
            if astr == "" or len(astr) == 0:
                continue
            tmpList = astr.strip().split("|")
            if len(tmpList) < 2:
                continue
            self.app.stkNameDict[tmpList[0]] = tmpList[1]

        refParam = {}
        refParam[CONSTS.S_APP] = self.app
        refParam["SelfGroupIndex"] = self.selfgroup_index
        refParam["SelfGroupName"] = self.selfgroup_id.text
        refParam["SelfStkList"] = list(self.selfStkList)
        stcLayout = SelfStkSetting(refParam)
        self.stcLayout = stcLayout
        self.self_setting_popup = SPopup(title="自選設定",
                                         content=stcLayout,
                                         size_hint=(None, None),
                                         size=(360, 480),
                                         auto_dismiss=False)
        stcLayout.ensurebtn_id.bind(on_press=self._changeGroup)
        stcLayout.cancelbtn_id.bind(on_press=self._self_setting_popup_dismiss)
        self.self_setting_popup.title_font = CONSTS.FONT_NAME
        self.self_setting_popup.open()

    def _self_setting_popup_dismiss(self, instance):
        self.self_setting_popup.dismiss()
        self.self_setting_popup.clear_widgets()

    def _changeGroup(self, instance):
        self.stcLayout.saveData()
        self._self_setting_popup_dismiss(instance)
        selfgroup_index = self.stcLayout.selfgroup_index
        selfgroup_name = self.stcLayout.selfgroup_name_id.text
        self.selfgroup_id.text = selfgroup_name
        adropdownBtn = self.dropDownDict[str(selfgroup_index)]
        adropdownBtn.text = selfgroup_name
        self.selfStkList = list(self.stcLayout.selfStkList)
        self.selfDict[selfgroup_index][1] = selfgroup_name
        stkListStr = ""
        for stkId in self.selfStkList:
            stkListStr += stkId + "|"
        if len(stkListStr) != 0:
            stkListStr = stkListStr[0:-1]
        self.selfDict[selfgroup_index][2] = stkListStr
        self.stkquote.clearQuote()  #變更自選組合,先清掉之前的畫面
        self._calcPageInfo()
        self.subscribeQuote()  #重新訂閱股票

    def _changeFields(self, instance):
        self.sfsLayout.saveData()
        self.self_fieldsetting_popup.dismiss(instance)

        self.stkquote.resetFieldsSeq(self.sfsLayout.fieldSeqList)  #變更欄位順序

    def doQuoteStart(self, instance):
        threading.Thread(target=self.doQuote).start()

    def _on_page_id_enter(self, instance):
        topage_num = int(instance.text)
        pageNum = 0
        if topage_num < 1:
            pageNum = 1
        elif topage_num > self.max_page_num:
            pageNum = self.max_page_num
        else:
            pageNum = topage_num
        self.page_id.text = str(pageNum)
        if pageNum == self.page_num:
            return

        self.page_num = pageNum

        self.stkquote.clearQuote()  #變更自選組合,先清掉之前的畫面
        self.subscribeQuote()  #重新訂閱股票

    def _onChangePage(self, changePage):
        if changePage == "NextPage":
            if self.page_num == self.max_page_num:
                self.page_num = 1
            else:
                self.page_num += 1
        elif changePage == "PrePage":
            if self.page_num == 1:
                self.page_num = self.max_page_num
            else:
                self.page_num -= 1
        else:
            topage_num = int(changePage)
            if topage_num < 1:
                self.page_num = 1
            elif topage_num > self.max_page_num:
                self.page_num = self.max_page_num
            self.topage_txt = str(self.page_num)

        self.page_id.text = str(self.page_num)

        self.prepage_id.disabled = True
        self.nextpage_id.disabled = True

        self.stkquote.clearQuote()  #變更自選組合,先清掉之前的畫面
        self.subscribeQuote()  #重新訂閱股票

        self.prepage_id.disabled = False
        self.nextpage_id.disabled = False

    def _calcPageInfo(self):
        stkListNum = len(self.selfStkList)
        if stkListNum == 0:
            self.prepage_id.disabled = True
            self.nextpage_id.disabled = True
            self.fieldRight_id.disabled = True
            self.fieldLeft_id.disabled = True
            self.page_id.text = "1"
            self.page_id.disabled = True
            self.totalpage_id.text = "1"
            return

        self.max_page_num = int(stkListNum / self.num_per_page)
        tmpNum = stkListNum % self.num_per_page
        if tmpNum != 0:
            self.max_page_num += 1
        if self.max_page_num == 1:
            self.prepage_id.disabled = True
            self.nextpage_id.disabled = True
        else:
            self.prepage_id.disabled = False
            self.nextpage_id.disabled = False
        if self.page_num > self.max_page_num:
            self.page_num = self.max_page_num

        self.page_id.text = str(self.page_num)
        self.totalpage_id.text = str(self.max_page_num)

        if self.max_page_num == 1:
            self.page_id.disabled = True
        else:
            self.page_id.disabled = False
        self.fieldRight_id.disabled = False
        self.fieldLeft_id.disabled = False

    def _onFieldShift(self, changePage):
        if changePage == "fieldRight":
            self.fieldRight_id.disabled = True
            self.stkquote.nextField()
            self.fieldRight_id.disabled = False
        elif changePage == "fieldLeft":
            self.fieldLeft_id.disabled = True
            self.stkquote.previousField()
            self.fieldLeft_id.disabled = False

    def my_callback_func(self, a_result):
        if a_result.errcode != 0:
            self.app.showErrorView(False, a_result.errcode, a_result.errdes)
            return
        if a_result.stkid == None:
            return
        if a_result.stkid not in self.selfStkList:
            return
        if a_result.mesgtype == abxtoolkit.WATCH_TYPE.stkBase:
            aQuoteDict = self.quoteDataDict.get(a_result.stkid)
            if aQuoteDict == None:
                aQuoteDict = {}
                self.quoteDataDict[a_result.stkid] = aQuoteDict
            quoteList = []
            aDict = {}
            baseList = []
            baseDict = {}
            aDict["id"] = [a_result.stkid, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
            baseDict["id"] = a_result.stkid
            if "SID" in a_result.data:
                aDict["id"] = [
                    a_result.data["SID"], DEFAULT_FGCOLOR, DEFAULT_BGCOLOR
                ]
                aQuoteDict["id"] = a_result.data["SID"]
            if "SNT" in a_result.data:
                aDict["name"] = [
                    a_result.data["SNT"], DEFAULT_FGCOLOR, DEFAULT_BGCOLOR
                ]
                aQuoteDict["name"] = a_result.data["SNT"]
                baseDict["name"] = a_result.data["SNT"]
            if "OT" in a_result.data:
                baseDict["OT"] = a_result.data["OT"]
            if "CloseT" in a_result.data:
                baseDict["CloseT"] = a_result.data["CloseT"]
            if "Dec" in a_result.data:
                baseDict["Dec"] = a_result.data["Dec"]
            quoteList.append(aDict)
            self.stkquote.updateQuote(quoteList)
            baseList.append(baseDict)
            self.stkquote.updateBaseQuote(baseList)
        if a_result.mesgtype == abxtoolkit.WATCH_TYPE.stkInfo:
            aQuoteDict = self.quoteDataDict.get(a_result.stkid)
            if aQuoteDict == None:
                aQuoteDict = {}
                self.quoteDataDict[a_result.stkid] = aQuoteDict
            quoteList = []
            aDict = {}
            baseList = []
            baseDict = {}
            aDict["id"] = [a_result.stkid, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
            baseDict["id"] = a_result.stkid
            if "YP" in a_result.data:
                aDict["YP"] = [
                    "{:.2f}".format(a_result.data["YP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
                aQuoteDict["YP"] = a_result.data["YP"]
                self._calcUpDown(a_result.stkid, aDict)
                baseDict["YP"] = a_result.data["YP"]
            if "USP" in a_result.data:
                aDict["USP"] = [
                    "{:.2f}".format(a_result.data["USP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "DSP" in a_result.data:
                aDict["DSP"] = [
                    "{:.2f}".format(a_result.data["DSP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "LTD" in a_result.data:
                baseDict["LTD"] = a_result.data["LTD"]
            quoteList.append(aDict)
            self.stkquote.updateQuote(quoteList)
            baseList.append(baseDict)
            self.stkquote.updateBaseQuote(baseList)
        if a_result.mesgtype == abxtoolkit.WATCH_TYPE.trade:
            aQuoteDict = self.quoteDataDict.get(a_result.stkid)
            if aQuoteDict == None:
                aQuoteDict = {}
                self.quoteDataDict[a_result.stkid] = aQuoteDict
            quoteList = []
            aDict = {}
            aDict["id"] = [a_result.stkid, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
            if "TT" in a_result.data:
                aDict["TT"] = [
                    sutil.formatTime(a_result.data["TT"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "TP" in a_result.data:
                aDict["TP"] = [
                    "{:.2f}".format(a_result.data["TP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
                aQuoteDict["TP"] = a_result.data["TP"]
                self._calcUpDown(a_result.stkid, aDict)
            if "TV" in a_result.data:
                aDict["TV"] = [
                    str(a_result.data["TV"]), DEFAULT_FGCOLOR, DEFAULT_BGCOLOR
                ]
            quoteList.append(aDict)
            self.stkquote.updateQuote(quoteList)
        if a_result.mesgtype == abxtoolkit.WATCH_TYPE.others:
            quoteList = []
            aDict = {}
            aDict["id"] = [a_result.stkid, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
            if "OP" in a_result.data:
                aDict["OP"] = [
                    "{:.2f}".format(a_result.data["OP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "HP" in a_result.data:
                aDict["HP"] = [
                    "{:.2f}".format(a_result.data["HP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "LP" in a_result.data:
                aDict["LP"] = [
                    "{:.2f}".format(a_result.data["LP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            quoteList.append(aDict)
            self.stkquote.updateQuote(quoteList)
        if a_result.mesgtype == abxtoolkit.WATCH_TYPE.order_1:
            quoteList = []
            aDict = {}
            aDict["id"] = [a_result.stkid, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR]
            if "BP" in a_result.data:
                aDict["BP"] = [
                    "{:.2f}".format(a_result.data["BP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "BV" in a_result.data:
                aDict["BV"] = [
                    str(a_result.data["BV"]), DEFAULT_FGCOLOR, DEFAULT_BGCOLOR
                ]
            if "AP" in a_result.data:
                aDict["AP"] = [
                    "{:.2f}".format(a_result.data["AP"]), DEFAULT_FGCOLOR,
                    DEFAULT_BGCOLOR
                ]
            if "AV" in a_result.data:
                aDict["AV"] = [
                    str(a_result.data["AV"]), DEFAULT_FGCOLOR, DEFAULT_BGCOLOR
                ]
            quoteList.append(aDict)
            self.stkquote.updateQuote(quoteList)

    def _calcUpDown(self, stkid, aDict):
        aQuoteDict = self.quoteDataDict.get(stkid)
        yp = aQuoteDict.get("YP")  #昨收價
        if yp == None:
            return
        tp = aQuoteDict.get("TP")  #成交價
        if tp == None:
            return
        upDown = tp - yp
        fgColor = None
        if upDown < 0:
            fgColor = DEFAULT_DOWNCOLOR
        elif upDown > 0:
            fgColor = DEFAULT_UPCOLOR
        else:
            fgColor = DEFAULT_FGCOLOR
        aDict["UD"] = ["{:.2f}".format(upDown), fgColor, DEFAULT_BGCOLOR]
        aDict["TP"] = ["{:.2f}".format(tp), fgColor, DEFAULT_BGCOLOR]

    def closeStkQuote(self):

        abxtoolkit.remove_all_listener()

    def doQuote(self):

        r = abxtoolkit.add_listener([self.my_callback_func])

        if self.selfgroup_index not in self.selfDict:
            return
        selfStkListStr = self.selfDict.get(self.selfgroup_index)[2]
        if selfStkListStr == "" or len(selfStkListStr) == 0:
            self._calcPageInfo()
            return

        self.selfStkList = selfStkListStr.split("|")
        self._calcPageInfo()
        self.subscribeQuote()

    def subscribeQuote(self):

        if len(self.selfStkList) == 0:
            quote_condition = []
        else:
            startIdx = (self.page_num - 1) * NUM_PER_PAGE
            endIdx = self.page_num * NUM_PER_PAGE
            if endIdx > len(self.selfStkList):
                endIdx = len(self.selfStkList)
            subscribeList = []
            quote_condition = []
            for idx in range(startIdx, endIdx):
                stkId = self.selfStkList[idx]
                if stkId == "" or len(stkId) == 0:
                    continue
                a_sub_stock = abxtoolkit.abx_quote_condition()
                a_sub_stock.stockID = stkId
                a_sub_stock.quoteID = [
                    'stkBase', 'stkInfo', 'order_1', 'trade', 'others'
                ]
                quote_condition.append(a_sub_stock)
                subscribeList.append(stkId)

            self.stkquote.setStkList(self.selfStkList)
            self.stkquote.setSubscribeList(subscribeList)
            self.stkquote.setGroupName(self.selfgroup_id.text)

        r = abxtoolkit.subscribe_quote(quote_condition)
Beispiel #7
0
class SExecTrade(BoxLayout):
    
    rowdata_id = ObjectProperty(None)
    strategy_id = ObjectProperty(None)
    savefile_id = ObjectProperty(None)
    ensurebtn_id = ObjectProperty(None)
    closebtn_id = ObjectProperty(None)
    
    def __init__(self, paramDict, **kwargs):
        super(SExecTrade, self).__init__(**kwargs)
        
        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)
        self.sysConfDict = self.app.confDict.get(CONSTS.SYS_CONF_DICT)
        self.strategyDict = {}
        
        self.rowdata_id.bind(focus=self.onRowdataFocus)
        
        self.strategyDropDown = SStrategyDropDown()
        firstRecord = True
        strategyList = None
        filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "strategy.ini")
        alist = sutil.getListFromFile(filePath)
        for astr in alist:
            strategyList = astr.strip().split(",")
            if len(strategyList) < 2:
                continue
            if firstRecord:
                firstRecord = False
                self.strategy_id.text = strategyList[0]
            self.strategyDict[strategyList[0]] = strategyList
            abtn = SButton(text=strategyList[0])
            abtn.size_hint_y = None
            abtn.height = 30
            abtn.bind(on_release=self.strategyDropDown.select)
            self.strategyDropDown.add_widget(abtn)
            
        self.strategy_id.bind(on_release=self.strategyDropDown.open)
        self.strategyDropDown.bind(on_select=self.strategySelect)
        
        self.savefile_id.bind(focus=self.onSavefileFocus)
    
    def onRowdataFocus(self, instance, value):
        if value:
            content = SFileSelectDialog(load=self.loadRowdataDir, cancel=self.dismiss_rowdataPopup)
            content.filechooser_id.path = rowdata_path
            popupTitle = self.sysConfDict.get("MSG_DOWNLOAD_FILE")
            self._rowdataPopup = SPopup(title=popupTitle, content=content, size_hint=(0.9, 0.9), title_font=CONSTS.FONT_NAME)
            self._rowdataPopup.open()
    
    def dismiss_rowdataPopup(self):
        self._rowdataPopup.dismiss()
    
    def loadRowdataDir(self, path, filename):
        if len(filename) == 0:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_FILE)
            return        
        self._rowdataPopup.dismiss()
        rowdata_path = path
        filenameTmp = filename[0][len(path) + 1:]
        self.rowdata_id.text = filenameTmp

        filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "user.ini")
        userConf = sutil.getDictFromFile(filePath)
        userConf["ROWDATA_DIR"] = path
        with open(filePath, 'w', encoding = 'utf-8') as f:
            for key in userConf.keys():
                value = userConf.get(key)
                aStr = key + "=" + value + "\n"
                f.write(aStr)
    
    def strategySelect(self, instance, atext):
        self.strategy_id.text = atext.text
    
    def onSavefileFocus(self, instance, value):
        if value:
            content = SFileInputDialog(load=self.loadSavefileDir, cancel=self.dismiss_savefilePopup)
            content.filechooser_id.path = data_path
            popupTitle = self.sysConfDict.get("MSG_DOWNLOAD_FILE")
            self._savefilePopup = SPopup(title=popupTitle, content=content, size_hint=(0.9, 0.9), title_font=CONSTS.FONT_NAME)
            self._savefilePopup.open()
    
    def dismiss_savefilePopup(self):
        self._savefilePopup.dismiss()
    
    def loadSavefileDir(self, path, filename):
        if len(filename) == 0:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_FILE)
            return
        self._savefilePopup.dismiss()
        data_path = path
        self.savefile_id.text = filename

        filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "user.ini")
        userConf = sutil.getDictFromFile(filePath)
        userConf["BACKTEST_SELECT_DIR"] = path[0:path.rfind(os.sep)]
        userConf["BACKTEST_DIR"] = path
        with open(filePath, 'w', encoding = 'utf-8') as f:
            for key in userConf.keys():
                value = userConf.get(key)
                aStr = key + "=" + value + "\n"
                f.write(aStr)
Beispiel #8
0
class SBTMenu(BoxLayout):
    
    body_layout = ObjectProperty(None)
    exitLayout_id = ObjectProperty(None)
    sbacktest = None
    fileList = None
    app = None
    
    confDict = {}
    filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "msgcode.ini")
    confDict[CONSTS.MSG_CODE_DICT] = sutil.getDictFromFile(filePath)
    filePath = os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "sysconf_zh_tw.ini")
    confDict[CONSTS.SYS_CONF_DICT] = sutil.getDictFromFile(filePath)    

    def __init__(self, paramDict, **kwargs):
        super(SBTMenu, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)
        
        userConf = sutil.getDictFromFile(os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "user.ini"))
        bt_file = userConf.get("BACKTEST_FILE")
        if bt_file != None and bt_file != "":
            self.fileList = bt_file.split(",")
            aflag = False
            for afile in self.fileList:
                afilePath = os.path.join(bk_file_dir, afile)
                if not os.path.exists(afilePath):
                    aflag = True
                    break
            if not aflag:
                if self.body_layout != None:
                    self.remove_widget(self.body_layout)
                refDict = {}
                for key in self.paramDict.keys():
                    refDict[key] = self.paramDict[key]
                refDict["fileDir"] = bk_file_dir
                refDict["fileList"] = self.fileList
                refDict[CONSTS.S_BTMENU] = self
                self.sbacktest = SBacktest(refDict)
                self.body_layout = self.sbacktest
                self.body_layout.size_hint = (1, .95)
                self.body_layout.pos_hint = {'x':0,'y':0}
                self.add_widget(self.body_layout, index=0)
        
        subMenu = self.paramDict.get("SUBMENU")
        if subMenu != None:
            if subMenu == False:
                exitBtn = SButton(text="離開", size_hint=(1, 1))
                exitBtn.halign = "center"
                exitBtn.valign = "middle"
                exitBtn.bind(on_release=self.closeWindows)
                self.exitLayout_id.add_widget(exitBtn)

    def closeWindows(self, obj):
        if self.app != None:
            self.app.closeWindows()

    def stradeCost(self):
        self.stcLayout = STradeCost({CONSTS.S_APP:self.app})
        popup = SPopup(title="交易成本設定", content=self.stcLayout,
                size_hint=(None, None), size=(640, 480), auto_dismiss=False)
        self.stcLayout.closebtn_id.bind(on_press=popup.dismiss)
        popup.title_font = CONSTS.FONT_NAME
        popup.open()
    
    def sselectFile(self):
        self.ssfLayout = SSelectFile({CONSTS.S_APP:self.app})
        self.ssf_popup = SPopup(title="選擇回測檔案", content=self.ssfLayout,
                size_hint=(None, None), size=(540, 480), auto_dismiss=False)
        self.ssfLayout.ensurebtn_id.bind(on_press=self.finishedSelectFiles)
        self.ssfLayout.closebtn_id.bind(on_press=self.ssf_popup.dismiss)
        self.ssf_popup.title_font = CONSTS.FONT_NAME
        self.ssf_popup.open()
    
    def finishedSelectFiles(self, instance):
        fileCount = len(self.ssfLayout.rightrv_id.data)
        if fileCount == 0:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_FILE)
            return
        self.ssf_popup.dismiss()
        self.saveUserConf()
        
        if self.fileList != None:
            self.fileList.clear()
        else:
            self.fileList = []
        for adict in self.ssfLayout.rightrv_id.data:
            self.fileList.append(adict.get("text"))
        if self.sbacktest == None:
            self.remove_widget(self.body_layout)
            refDict = {}
            for key in self.paramDict.keys():
                refDict[key] = self.paramDict[key]
            refDict["fileDir"] = self.ssfLayout.filepath
            refDict["fileList"] = self.fileList
            refDict[CONSTS.S_BTMENU] = self
            self.sbacktest = SBacktest(refDict)
            self.body_layout = self.sbacktest
            self.body_layout.size_hint = (1, .96)
            self.body_layout.pos_hint = {'x':0,'y':0}
            self.add_widget(self.body_layout, index=0)
        else:
            self.sbacktest.loadFile(self.ssfLayout.filepath, self.fileList)
    
    def saveUserConf(self):
        filePath = os.path.join(os.path.dirname(__file__), "../conf/user.ini")
        userConf = sutil.getDictFromFile(filePath)
        userConf["BACKTEST_SELECT_DIR"] = self.ssfLayout.filedir
        userConf["BACKTEST_DIR"] = self.ssfLayout.filepath
        backtest_file = ""        
        for adict in self.ssfLayout.rightrv_id.data:
            backtest_file += adict.get("text") 
            backtest_file += ","
        backtest_file = backtest_file[0:-1]
        userConf["BACKTEST_FILE"] = backtest_file
        with open(filePath, 'w', encoding = 'utf-8') as f:
            for key in userConf.keys():
                value = userConf.get(key)
                aStr = key + "=" + value + "\n"
                f.write(aStr)
        
    def analyzeBacktest(self):
        if self.sbacktest != None:
            if self.sbacktest.dataList != None and len(self.sbacktest.dataList) != 0:
                refDict = {}
                for key in self.paramDict.keys():
                    refDict[key] = self.paramDict.get(key)
                refDict["dataList"] = self.sbacktest.dataList
                refDict["fileList"] = self.fileList
                refDict[CONSTS.S_BTMENU] = self
                self.strLayout = STradeReport(refDict)
                self.str_popup = SPopup(title="分析報表", content=self.strLayout,
                        size_hint=(None, None), size=(800, 600), auto_dismiss=False)
                self.strLayout.closebtn_id.bind(on_press=self.str_popup.dismiss)
                self.str_popup.title_font = CONSTS.FONT_NAME
                self.str_popup.open()
            else:
                self.app.showErrorView(True, CONSTS.ERR_NO_BACKTEST_DATA)
        else:
            self.app.showErrorView(True, CONSTS.ERR_NOT_EXECUTE_BACKTEST)
Beispiel #9
0
class SUniteMenu(FloatLayout):

    menuId = ObjectProperty(None)
    body_layout = ObjectProperty(None)
    content_layout = ObjectProperty(None)
    btMenu = ObjectProperty(None)
    app = None
    menuLayout = ObjectProperty(None)
    sosLayout = None
    sosPopup = None
    sbacktest = None
    selfStkQuote = None
    sselectStock = None
    fileList = None

    def __init__(self, paramDict, **kwargs):
        super(SUniteMenu, self).__init__(**kwargs)

        self.paramDict = paramDict
        self.app = self.paramDict.get(CONSTS.S_APP)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="用戶中心",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="交易執行",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="交易分析",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="智慧選股",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        mbtn.bind(on_release=self.optionSelect)
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="股票報價",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        mbtn.bind(on_release=self.stockQuote)
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.01, 1)))
        mbtn = MenuButton(suniteMenu=self,
                          text="離開",
                          size_hint=(.15, 1),
                          halign="center",
                          valign="middle")
        mbtn.bind(on_release=self.closeWindows)
        self.menuId.add_widget(mbtn)

        self.menuId.add_widget(BoxLayout(size_hint=(.04, 1)))

    def closeWindows(self, instance):
        if self.app != None:
            self.app.closeWindows()

    def login(self, execType):
        self.execType = execType
        self.loginLayout = SLogin({CONSTS.S_APP: self.app})
        self.loginPopup = Popup(title="登入",
                                content=self.loginLayout,
                                size_hint=(None, None),
                                size=(400, 300),
                                auto_dismiss=False)
        self.loginLayout.closebtn_id.bind(on_press=self.loginPopup.dismiss)
        self.loginLayout.loginbtn_id.bind(on_press=self.loginProcess)
        self.loginPopup.title_font = CONSTS.FONT_NAME
        self.loginPopup.open()

    def loginProcess(self, instance):
        Clock.schedule_once(self.loginSchedule)

    def loginSchedule(self, instance):
        self.event = Clock.schedule_interval(self.loginCheck, .0005)
        threading.Thread(target=self.toolkitLogin).start()

    def loginCheck(self, dt):
        if self.loginLayout.loginFlag != None:
            self.event.cancel()
            if self.loginLayout.loginFlag == True:
                self.app.loginFlag = True
                self.app.accountIdList = self.loginLayout.accountIdList
                self.app.account = self.loginLayout.user_id.text
                self.app.pwd = self.loginLayout.pwd_id.text
                self.loginPopup.dismiss()
                if self.execType == "query":
                    self.openWebBrowser()
                elif self.execType == "download":
                    self.downloadData()
                elif self.execType == "optionSelect":
                    self.doOptionSelect()
                elif self.execType == "stockQuote":
                    self.doStockQuote()

    def toolkitLogin(self):
        self.loginLayout.login()

    def removeMenu(self):
        if self.menuLayout == None:
            return
        self.remove_widget(self.menuLayout)

    def userMenu(self, instance):

        width = instance.size[0] + 10
        x1 = instance.pos[0]
        y1 = instance.pos[1] - 63
        self.menuLayout = MenuLayout(suniteMenu=self,
                                     size_hint=(None, None),
                                     size=(width, instance.size[1]),
                                     pos=[x1, y1],
                                     orientation="vertical")

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="用戶註冊")
        btn.bind(on_press=self.registerUser)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="帳務查詢")
        btn.bind(on_press=self.query)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))

        self.add_widget(self.menuLayout)
        self.menuLayout.layoutHeight = 63

        return self.menuLayout

    def registerUser(self, instance):
        self.removeMenu()
        aDict = sutil.getDictFromFile(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "user.ini"))
        webbrowser.open(aDict.get("WEB_REGISTER_URL"))

    def query(self, instance):
        self.removeMenu()
        if self.app.loginFlag == False:
            self.login("query")
        else:
            self.openWebBrowser()

    def openWebBrowser(self):
        urlParam = "dataID=" + self.app.account + "&dataCheck=" + self.app.pwd
        aDict = sutil.getDictFromFile(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "user.ini"))
        webbrowser.open(aDict.get("WEB_LOGIN_URL") + urlParam, new=0)

    def executeMenu(self, instance):

        width = instance.size[0] + 40
        x1 = instance.pos[0]
        y1 = instance.pos[1] - 125
        self.menuLayout = MenuLayout(suniteMenu=self,
                                     size_hint=(None, None),
                                     size=(width, instance.size[1]),
                                     pos=[x1, y1],
                                     orientation="vertical")

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="歷史報價下載")
        btn.bind(on_press=self.downloadProcess)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None),
                            height=30,
                            text="ABXToolkit使用說明")
        btn.bind(on_press=self.explain)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="交易策略設定")
        btn.bind(on_press=self.strategySetting)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="執行交易程式")
        btn.bind(on_press=self.executeTrade)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))

        self.add_widget(self.menuLayout)
        self.menuLayout.layoutHeight = 125

        return self.menuLayout

    def downloadProcess(self, instance):
        self.removeMenu()
        if self.app.loginFlag == False:
            self.login("download")
        else:
            self.downloadData()

    def downloadData(self):
        downloadLayout = SDownload({CONSTS.S_APP: self.app})
        popup = SPopup(title="下載歷史報價資料",
                       content=downloadLayout,
                       size_hint=(None, None),
                       size=(540, 400),
                       auto_dismiss=False)
        downloadLayout.closebtn_id.bind(on_press=popup.dismiss)
        popup.title_font = CONSTS.FONT_NAME
        popup.open()

    def explain(self, instance):
        self.removeMenu()
        aDict = sutil.getDictFromFile(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "user.ini"))
        webbrowser.open(aDict.get("WEB_EXPLAIN_URL"), new=0)

    def strategySetting(self, instance):
        self.removeMenu()
        self.ssyLayout = SStrategy({CONSTS.S_APP: self.app})
        popup = SPopup(title="交易策略設定",
                       content=self.ssyLayout,
                       size_hint=(None, None),
                       size=(640, 480),
                       auto_dismiss=False)
        self.ssyLayout.closebtn_id.bind(on_press=popup.dismiss)
        popup.title_font = CONSTS.FONT_NAME
        popup.open()

    def executeTrade(self, instance):
        self.removeMenu()
        self.etLayout = SExecTrade({CONSTS.S_APP: self.app})
        self.et_popup = SPopup(title="執行交易程式",
                               content=self.etLayout,
                               size_hint=(None, None),
                               size=(360, 280),
                               auto_dismiss=False)
        self.etLayout.ensurebtn_id.bind(on_press=self.execTradeEvent)
        self.etLayout.closebtn_id.bind(on_press=self.et_popup.dismiss)
        self.et_popup.title_font = CONSTS.FONT_NAME
        self.et_popup.open()

    def execTradeEvent(self, instance):

        rowdataName = self.etLayout.rowdata_id.text
        strategyName = self.etLayout.strategy_id.text
        savefileName = self.etLayout.savefile_id.text
        if rowdataName == "":
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_HISTORY_DATA)
            return
        elif strategyName == "":
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_STRATEGY)
            return
        elif savefileName == "":
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_SAVEFILE)
            return

        strategy_dir = os.path.abspath(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "strategy"))
        strategyData = None
        if strategyName != "":
            alist = sutil.getListFromFile(
                os.path.join(os.path.dirname(__file__),
                             ".." + os.sep + "conf" + os.sep + "strategy.ini"))
            for astr in alist:
                strategyList = astr.strip().split(",")
                if len(strategyList) < 2:
                    continue
                if strategyName == strategyList[0]:
                    strategyData = strategyList[1]
            isExistFlag = True
            if strategyData != None:
                filePath = os.path.join(strategy_dir, strategyData)
                if os.path.exists(filePath) != True:
                    isExistFlag = False
            else:
                isExistFlag = False
            if isExistFlag == False:
                msgCodeDict = self.app.confDict.get(CONSTS.MSG_CODE_DICT)
                msgText = msgCodeDict.get(CONSTS.ERR_STRATEGY_FILE_NOT_FOUND)
                self.app.showErrorView(False, strategyName, msgText)
                return

        userConf = sutil.getDictFromFile(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "user.ini"))
        rowdata_dir = userConf.get("ROWDATA_DIR")
        data_dir = userConf.get("BACKTEST_DIR")

        self.rowdata_file = os.path.join(rowdata_dir, rowdataName)
        self.strategy_file = os.path.join(strategy_dir, strategyData)
        self.savefile_file = os.path.join(data_dir, savefileName)

        self.doPtradeEvent()

    def doPtradeEvent(self):
        contentLayout = BoxLayout()
        contentLayout.orientation = "vertical"
        contentLayout.size_hint = (1, 1)
        contentLabel = SLabel(text="  交易執行中...", size_hint=(1, .8))
        contentLayout.add_widget(contentLabel)

        sysConfDict = self.app.confDict.get(CONSTS.SYS_CONF_DICT)

        self.result = None
        self.dp_popup = Popup(title=sysConfDict.get("MSG_TITLE"),
                              content=contentLayout,
                              size_hint=(None, None),
                              size=(160, 120),
                              auto_dismiss=False)
        self.dp_popup.title_font = CONSTS.FONT_NAME
        self.dp_popup.bind(on_open=self.dp_open)
        Clock.schedule_once(self.doPtradeStart)

    def doPtradeStart(self, instance):
        self.dp_popup.open()
        threading.Thread(target=self.toolkitPtrade).start()

    def toolkitPtrade(self):
        self.result = abxtoolkit.do_ptrade(self.rowdata_file,
                                           self.strategy_file,
                                           self.savefile_file)

    def doPtrade_check(self, dt):
        if self.result != None:
            self.dp_popup.dismiss()
            self.event.cancel()
            errCode = self.result.get("ErrCode")
            if errCode != 0:
                errDesc = self.result.get("ErrDesc")
                self.app.showErrorView(False, errCode, errDesc)
            else:
                self.finishedPopup()

    def dp_open(self, instance):
        self.event = Clock.schedule_interval(self.doPtrade_check, .0005)

    def finishedPopup(self):
        content = BoxLayout(size_hint=(1, 1), orientation="vertical")

        content.add_widget(BoxLayout(size_hint=(1, .4)))

        bottomLayout = BoxLayout(size_hint=(1, .2), orientation="horizontal")
        bottomLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        ensurebtn = SButton(text="確定", size_hint=(.8, .8))
        bottomLayout.add_widget(ensurebtn)
        bottomLayout.add_widget(BoxLayout(size_hint=(.1, 1)))
        content.add_widget(bottomLayout)

        content.add_widget(BoxLayout(size_hint=(1, .4)))

        self.fin_popup = SPopup(title="執行完成",
                                content=content,
                                title_font=CONSTS.FONT_NAME,
                                size_hint=(None, None),
                                size=(200, 100),
                                auto_dismiss=False)
        ensurebtn.bind(on_press=self.fin_popup.dismiss)
        self.fin_popup.open()

    def analyzeMenu(self, instance):

        width = instance.size[0] + 10
        x1 = instance.pos[0]
        y1 = instance.pos[1] - 94
        self.menuLayout = MenuLayout(suniteMenu=self,
                                     size_hint=(None, None),
                                     size=(width, instance.size[1]),
                                     pos=[x1, y1],
                                     orientation="vertical")

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="回測")
        btn.bind(on_press=self.sselectFile)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="交易分析")
        btn.bind(on_press=self.analyzeBacktest)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))
        btn = SubMenuButton(size_hint=(1, None), height=30, text="交易成本設定")
        btn.bind(on_press=self.stradeCost)
        self.menuLayout.add_widget(btn)

        self.menuLayout.add_widget(BoxLayout(size_hint=(1, None), height=1))

        self.add_widget(self.menuLayout)
        self.menuLayout.layoutHeight = 94

        return self.menuLayout

    def sselectFile(self, instance):
        self.removeMenu()
        self.ssfLayout = SSelectFile({CONSTS.S_APP: self.app})
        self.ssf_popup = SPopup(title="選擇回測檔案",
                                content=self.ssfLayout,
                                size_hint=(None, None),
                                size=(540, 480),
                                auto_dismiss=False)
        self.ssfLayout.ensurebtn_id.bind(on_press=self.finishedSelectFiles)
        self.ssfLayout.closebtn_id.bind(on_press=self.ssf_popup.dismiss)
        self.ssf_popup.title_font = CONSTS.FONT_NAME
        self.ssf_popup.open()

    def finishedSelectFiles(self, instance):
        fileCount = len(self.ssfLayout.rightrv_id.data)
        if fileCount == 0:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_FILE)
            return
        self.ssf_popup.dismiss()
        self.saveUserConf()

        if self.selfStkQuote != None:
            self.selfStkQuote.closeStkQuote()

        if self.fileList != None:
            self.fileList.clear()
        else:
            self.fileList = []
        for adict in self.ssfLayout.rightrv_id.data:
            self.fileList.append(adict.get("text"))
        if self.sbacktest == None:
            self.body_layout.remove_widget(self.content_layout)
            refDict = {}
            for key in self.paramDict.keys():
                refDict[key] = self.paramDict[key]
            refDict["fileDir"] = self.ssfLayout.filepath
            refDict["fileList"] = self.fileList
            self.sbacktest = SBacktest(refDict)
            self.content_layout = self.sbacktest
            self.content_layout.size_hint = (1, 1)
            self.body_layout.add_widget(self.content_layout)
        else:
            self.sbacktest.loadFile(self.ssfLayout.filepath, self.fileList)
        """if self.sbacktest == None:
            self.body_layout.remove_widget(self.content_layout)
            refDict = {}
            for key in self.paramDict.keys():
                refDict[key] = self.paramDict[key]
            refDict["fileDir"] = self.ssfLayout.filepath
            refDict["fileList"] = self.fileList
            self.sbacktest = SBacktest(refDict)
            self.content_layout = self.sbacktest
            self.content_layout.size_hint = (1, 1)
            self.body_layout.add_widget(self.content_layout)
        else:
            self.sbacktest.loadFile(self.ssfLayout.filepath, self.fileList)
        """
        self.body_layout.remove_widget(self.content_layout)
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict[key]
        refDict["fileDir"] = self.ssfLayout.filepath
        refDict["fileList"] = self.fileList
        self.sbacktest = SBacktest(refDict)
        self.content_layout = self.sbacktest
        self.content_layout.size_hint = (1, 1)
        self.body_layout.add_widget(self.content_layout)

    def saveUserConf(self):
        filePath = os.path.join(os.path.dirname(__file__),
                                ".." + os.sep + "conf" + os.sep + "user.ini")
        userConf = sutil.getDictFromFile(filePath)
        userConf["BACKTEST_SELECT_DIR"] = self.ssfLayout.filedir
        userConf["BACKTEST_DIR"] = self.ssfLayout.filepath
        backtest_file = ""
        for adict in self.ssfLayout.rightrv_id.data:
            backtest_file += adict.get("text")
            backtest_file += ","
        backtest_file = backtest_file[0:-1]
        userConf["BACKTEST_FILE"] = backtest_file
        with open(filePath, 'w', encoding='utf-8') as f:
            for key in userConf.keys():
                value = userConf.get(key)
                aStr = key + "=" + value + "\n"
                f.write(aStr)

    def analyzeBacktest(self, instance):
        self.removeMenu()
        if self.sbacktest != None:
            if self.sbacktest.dataList != None and len(
                    self.sbacktest.dataList) != 0:
                refDict = {}
                for key in self.paramDict.keys():
                    refDict[key] = self.paramDict.get(key)
                refDict["dataList"] = self.sbacktest.dataList
                refDict["fileList"] = self.fileList
                refDict[CONSTS.S_BTMENU] = self
                self.strLayout = STradeReport(refDict)
                self.str_popup = SPopup(title="分析報表",
                                        content=self.strLayout,
                                        size_hint=(None, None),
                                        size=(800, 600),
                                        auto_dismiss=False)
                self.strLayout.closebtn_id.bind(
                    on_press=self.str_popup.dismiss)
                self.str_popup.title_font = CONSTS.FONT_NAME
                self.str_popup.open()
            else:
                self.app.showErrorView(True, CONSTS.ERR_NO_BACKTEST_DATA)
        else:
            self.app.showErrorView(True, CONSTS.ERR_NOT_EXECUTE_BACKTEST)

    def stradeCost(self, instance):
        self.removeMenu()
        self.stcLayout = STradeCost({CONSTS.S_APP: self.app})
        popup = SPopup(title="交易成本設定",
                       content=self.stcLayout,
                       size_hint=(None, None),
                       size=(640, 480),
                       auto_dismiss=False)
        self.stcLayout.closebtn_id.bind(on_press=popup.dismiss)
        popup.title_font = CONSTS.FONT_NAME
        popup.open()

    def optionSelect(self, instance):
        if self.app.loginFlag == False:
            self.login("optionSelect")
        else:
            self.doOptionSelect()

    def doOptionSelect(self):
        if self.sosLayout == None:
            self.sosLayout = SOptionSelect({CONSTS.S_APP: self.app})
        else:
            self.sosPopup.open()
            return
        self.sosPopup = SPopup(title="智慧選股",
                               content=self.sosLayout,
                               size_hint=(None, None),
                               size=(640, 480),
                               auto_dismiss=False)
        self.sosLayout.ensurebtn_id.bind(on_press=self.execOptionResult)
        self.sosLayout.resetbtn_id.bind(on_press=self.resetOptionSelect)
        self.sosLayout.selectbtn_id.bind(on_press=self.showOptionSelect)
        self.sosLayout.closebtn_id.bind(on_press=self.optionPopupDismiss)
        self.sosPopup.title_font = CONSTS.FONT_NAME
        self.sosPopup.open()

    def execOptionResult(self, instance):
        if self.sosLayout.optionList == None:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_OPTION)
            return
        else:
            isSelectFlag = False
            for aObj in self.sosLayout.optionList:
                if aObj.isSelected():
                    isSelectFlag = True
                    break
            if isSelectFlag == False:
                self.app.showErrorView(True, CONSTS.ERR_UNSELECT_OPTION)
                return
        self.optionPopupDismiss(instance)

        fidList = []
        for aObj in self.sosLayout.optionList:
            if aObj.isSelected():
                fidList.append(aObj.getValueDict())

        self.body_layout.remove_widget(self.content_layout)
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict[key]
        refDict["fidList"] = fidList
        self.sselectStock = SSelectStock(refDict)
        self.content_layout = self.sselectStock
        self.content_layout.size_hint = (1, 1)
        self.body_layout.add_widget(self.content_layout)

    def resetOptionSelect(self, instance):
        self.sosLayout.setToOptionDefault()

    def showOptionSelect(self, instance):
        if self.sosLayout.optionList == None:
            self.app.showErrorView(True, CONSTS.ERR_UNSELECT_OPTION)
            return
        else:
            isSelectFlag = False
            for aObj in self.sosLayout.optionList:
                if aObj.isSelected():
                    isSelectFlag = True
                    break
            if isSelectFlag == False:
                self.app.showErrorView(True, CONSTS.ERR_UNSELECT_OPTION)
                return
        self.sosLayout.showSelectedOptionDesc()

    def optionPopupDismiss(self, instance):
        self.sosPopup.dismiss()

    def stockQuote(self, instance):
        self.removeMenu()
        if self.app.loginFlag == False:
            self.login("stockQuote")
        else:
            self.doStockQuote()

    def doStockQuote(self):
        self.body_layout.remove_widget(self.content_layout)
        refDict = {}
        for key in self.paramDict.keys():
            refDict[key] = self.paramDict[key]
        self.selfStkQuote = SelfStkQuote(refDict)
        self.content_layout = self.selfStkQuote
        self.content_layout.size_hint = (1, 1)
        self.body_layout.add_widget(self.content_layout)