Пример #1
0
    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)

        aKey = self.keyList[self.scopeIdx[0] + index]
        aDict = self.dataDict.get(aKey)

        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = sutil.formatDateTime(aKey)

        self.infoLayout.add_widget(self.info_vol)
        volume = aDict.get("VOL")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(volume)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(volume)
        else:
            valueStr = str(volume)
        self.info_vol.text = valueStr

        maxLength = len(self.info_time.text)
        if maxLength < schartutil.calcCharNum(self.info_vol.text):
            maxLength = schartutil.calcCharNum(self.info_vol.text)

        layoutWidth = schartutil.getInfoLayoutWidth(maxLength)
        self.infoLayout.col_default_width = layoutWidth
        self.infoLayout.size = [layoutWidth, 44]

        x1 = self.chartPos[0] + (index + 1) * (self.tickWide +
                                               self.tickGap) - self.backGap
        halfNum = int(self.dispNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.chartPos[1] + self.chartSize[1] - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)
Пример #2
0
    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.col_default_width = 90
            self.infoLayout.size = [90, 64]
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)
        x1 = self.start_xaxis + index * self.xscale
        halfNum = int(self.chartNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.volume_yaxis + self.crossLine_height - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)

        dataDict = self.minTimeList[index]

        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = "時:" + sutil.formatTime(dataDict.get("TD"))

        price = dataDict.get("CloseP")
        self.infoLayout.add_widget(self.info_price)
        self.info_price.text = "價:" + ("{:7.2f}".format(price)).strip()
        self.info_price.color = self._getPriceColor(self.yesPrice, price)

        self.infoLayout.add_widget(self.info_vol)
        self.info_vol.text = "量:" + ("{:13.0f}".format(
            dataDict.get("Vol"))).strip()
Пример #3
0
class SMinuteTimeChart():

    removeXCordList = None
    removePriceYCordList = None
    removeVolumeYCordList = None
    maxVolume = None
    crossLineIndex = None
    infoLayout = None

    def __init__(self, paramDict):

        self.paramDict = paramDict

        self.layout = self.paramDict.get("Layout")  #繪圖之layout
        self.canvas = self.paramDict.get("Canvas")  #繪圖之canvas
        self.shift_left = self.paramDict.get("SHIFT_LEFT")  #圖形左邊位移距離
        self.shift_gapheight = self.paramDict.get("SHIFT_GAPHEIGHT")  #價圖及量圖的間距
        self.shift_bottom = self.paramDict.get("SHIFT_BOTTOM")  #圖形底部位移距離
        self.shift_top = self.paramDict.get("SHIFT_TOP")  #圖形上方位移距離
        self.price_height_per = self.paramDict.get("PRICE_HEIGHT_PER")  #價圖高度佔比
        self.volume_height_per = self.paramDict.get(
            "VOLUME_HEIGHT_PER")  #量圖高度佔比
        self.CORD_INFO_COLOR = self.paramDict.get(
            "CORD_INFO_COLOR")  #座標資訊的文字顏色
        self.DATA_INFO_COLOR = self.paramDict.get("DATA_INFO_COLOR")  #資訊的文字顏色
        self.UP_COLOR = self.paramDict.get("UP_COLOR")  #上漲時線條顏色
        self.DOWN_COLOR = self.paramDict.get("DOWN_COLOR")  #下跌時線條顏色
        self.EQUAL_COLOR = self.paramDict.get("EQUAL_COLOR")  #持平時線條顏色
        self.VOLUME_COLOR = self.paramDict.get("VOLUME_COLOR")  #量的線條顏色
        self.FRAME_COLOR = self.paramDict.get("FRAME_COLOR")  #邊框的線條顏色
        self.GRID_COLOR = self.paramDict.get("GRID_COLOR")  #格線的線條顏色
        self.CROSS_LINE_COLOR = self.paramDict.get(
            "CROSS_LINE_COLOR")  #十字線線條顏色
        self.UP_DOWN_PER = self.paramDict.get("UP_DOWN_PER")  #漲跌幅度

        self.chartNum = self.paramDict.get("ChartNum")  #時間總筆數
        self.yesPrice = self.paramDict.get("YesPrice")  #昨收價
        self.startTime = self.paramDict.get("StartTime")  #起始時間
        self.endTime = self.paramDict.get("EndTime")  #截止時間
        self.infoFunc = self.paramDict.get("InfoFunc")  #顯示訊息之函式
        self.instGroup = self.paramDict.get("InstGroup",
                                            "")  #InstructionGroup所使用之group值

        self.minTimeList = []  #分時資料List
        self.volumeList = []  #成交量的List
        self.lastMinTime = None  #最後一筆之時間

        self.info_time = SLabel(text="")  #時間
        self.info_time.color = self.DATA_INFO_COLOR
        self.info_price = SLabel(text="")  #成交價
        self.info_vol = SLabel(text="")  #成交量
        self.info_vol.color = self.DATA_INFO_COLOR

    def _calcChartInfo(self):
        self.price_width = self.chart_size[0] - self.shift_left
        drawHeight = self.chart_size[
            1] - self.shift_bottom - self.shift_gapheight - self.shift_top
        self.price_height = drawHeight * self.price_height_per / (
            self.price_height_per + self.volume_height_per)
        self.volume_height = drawHeight * self.volume_height_per / (
            self.price_height_per + self.volume_height_per)
        self.xscale = 1.0 * self.price_width / self.chartNum  #走勢圖x軸縮放比例
        maxPrice = self.yesPrice * (1 + self.UP_DOWN_PER)  #最高價
        self.lowestPrice = self.yesPrice * (1 - self.UP_DOWN_PER)  #最低價
        self.price_yscale = 1.0 * self.price_height / (
            maxPrice - self.lowestPrice)  #價圖y軸縮放比例
        self._calcVolumeYScale()
        self.start_xaxis = self.chart_start_pos[
            0] + self.shift_left  #價圖及量圖之原點的x座標值
        self.price_yaxis = self.chart_start_pos[
            1] + self.shift_bottom + self.volume_height + self.shift_gapheight  #價圖之原點的y座標值
        self.volume_yaxis = self.chart_start_pos[
            1] + self.shift_bottom  #量圖之原點的y座標值
        self.crossLine_height = self.chart_size[
            1] - self.shift_bottom - self.shift_top  #十字線的高度

    def _calcVolumeYScale(self):
        if self.maxVolume == None:
            self.volume_yscale = 1.0 * self.volume_height / 100
        else:
            self.volume_yscale = 1.0 * self.volume_height / self.maxVolume

    def _drawNoDataGraph(self):
        """
        繪製一個沒有數據之圖形
        """
        self._calcChartInfo()
        self._drawFrameGrid()  #繪製一矩形
        self._drawPriceCord()  #繪製價圖y軸資訊及線條
        self._drawVolumeCord()  #繪製量圖y軸資訊及線條

    def _drawFrameGrid(self):
        # Start-01: 產生一繪製外框,線條及座標之物件
        rectParamDict = {}
        rectParamDict["layout"] = self.layout
        rectParamDict["canvas"] = self.canvas
        rectParamDict["width"] = self.price_width
        rectParamDict["height"] = self.crossLine_height
        rectParamDict["x_start_pos"] = self.start_xaxis
        rectParamDict["y_start_pos"] = self.volume_yaxis
        rectParamDict["xscale"] = self.xscale
        rectParamDict["yscale"] = self.price_yscale
        rectParamDict["rectColor"] = self.FRAME_COLOR
        rectParamDict["rectWidth"] = 1
        rectParamDict["gridColor"] = self.GRID_COLOR
        rectParamDict["gridWidth"] = 1
        rectParamDict["cordColor"] = self.CORD_INFO_COLOR
        rectParamDict["instGroup"] = self.instGroup + "_SMTC_Rect"
        rectParamDict["shift_left"] = self.shift_left
        rectParamDict["drawFlagList"] = [False, False]
        rectParamDict["formatFlag"] = True

        smintimeCordUtil = SMinTimeCordUtil(rectParamDict)
        # End-01.

        smintimeCordUtil.drawRectGrid()  #繪製一矩形框

        xCordDict = {}

        infoList = []
        aNum = -1
        for aTime in range(int(self.startTime), int(self.endTime) + 1):
            aRoundNum = aTime % 100
            if aRoundNum <= 59:
                aNum += 1
                if aRoundNum == 0:
                    infoList.append([aNum, int(aTime / 100)])

        xCordDict["infoList"] = infoList
        xCordDict["removeLabelList"] = self.removeXCordList
        self.removeXCordList = smintimeCordUtil.drawXTimeCord(
            xCordDict)  #繪製x軸資訊

    def _drawPriceCord(self):
        """
        """
        rectParamDict = {}
        rectParamDict["layout"] = self.layout
        rectParamDict["canvas"] = self.canvas
        rectParamDict["width"] = self.price_width
        rectParamDict["height"] = self.price_height
        rectParamDict["x_start_pos"] = self.start_xaxis
        rectParamDict[
            "y_start_pos"] = self.volume_yaxis + self.volume_height + self.shift_gapheight
        rectParamDict["xscale"] = self.xscale
        rectParamDict["yscale"] = self.price_yscale
        rectParamDict["rectColor"] = self.FRAME_COLOR
        rectParamDict["rectWidth"] = 1
        rectParamDict["gridColor"] = self.GRID_COLOR
        rectParamDict["gridWidth"] = 1
        rectParamDict["cordColor"] = self.CORD_INFO_COLOR
        rectParamDict["instGroup"] = "SMTC_Price"
        rectParamDict["shift_left"] = self.shift_left
        rectParamDict["drawFlagList"] = [True, False]
        rectParamDict["formatFlag"] = True

        smintimeCordUtil = SMinTimeCordUtil(rectParamDict)
        # 繪製y軸資訊
        price_yCordDict = {}
        infoList = []
        priceStep = 1.0 * (self.yesPrice - self.lowestPrice) / 4
        for idx in range(0, 9):
            if idx == 4:
                infoList.append(self.yesPrice)
            else:
                aPrice = self.lowestPrice + priceStep * idx * 1.0
                infoList.append(aPrice)
        price_yCordDict["infoList"] = infoList
        price_yCordDict["lowestValue"] = self.lowestPrice
        price_yCordDict["removeLabelList"] = self.removePriceYCordList
        self.removePriceYCordList = smintimeCordUtil.drawYGridCord(
            price_yCordDict)

    def _drawVolumeCord(self):
        """
        """
        rectParamDict = {}
        rectParamDict["layout"] = self.layout
        rectParamDict["canvas"] = self.canvas
        rectParamDict["width"] = self.price_width
        rectParamDict["height"] = self.volume_height
        rectParamDict["x_start_pos"] = self.start_xaxis
        rectParamDict["y_start_pos"] = self.volume_yaxis
        rectParamDict["xscale"] = self.xscale
        rectParamDict["yscale"] = self.volume_yscale
        rectParamDict["rectColor"] = self.FRAME_COLOR
        rectParamDict["rectWidth"] = 1
        rectParamDict["gridColor"] = self.GRID_COLOR
        rectParamDict["gridWidth"] = 1
        rectParamDict["cordColor"] = self.CORD_INFO_COLOR
        rectParamDict["instGroup"] = "SMTC_Volume"
        rectParamDict["shift_left"] = self.shift_left
        rectParamDict["drawFlagList"] = [False, True]
        rectParamDict["formatFlag"] = False

        smintimeCordUtil = SMinTimeCordUtil(rectParamDict)
        # 繪製y軸資訊
        volume_yCordDict = {}
        infoList = []
        infoList.append(0)
        if self.maxVolume == None:
            infoList.append(50)
            infoList.append(100)
        else:
            infoList.append(int(self.maxVolume / 2))
            infoList.append(self.maxVolume)

        volume_yCordDict["infoList"] = infoList
        volume_yCordDict["lowestValue"] = 0
        volume_yCordDict["removeLabelList"] = self.removeVolumeYCordList
        self.removeVolumeYCordList = smintimeCordUtil.drawYGridCord(
            volume_yCordDict)

    def charting(self, systemInfoList):
        """
        繪圖
        """
        #self.canvas.clear() 改由呼叫charting的那一層控制

        self.chart_start_pos = systemInfoList[
            0]  #走勢圖的原點座標,為一list物件,[0]為x座標,[1]為y座標
        self.chart_size = systemInfoList[1]  #走勢圖的size,為一list物件,[0]為寬度,[1]為高度

        if self.minTimeList == None or len(self.minTimeList) == 0:
            self._drawNoDataGraph()
            return

        self._calcChartInfo()
        self._drawFrameGrid()  #繪製一矩形
        self._drawPriceCord()  #繪製價圖y軸資訊及線條

        isFirst = True
        for aIdx in range(0, len(self.minTimeList)):
            aDict = self.minTimeList[aIdx]
            if isFirst == True:
                isFirst = False
                preDict = {}
                preDict["TD"] = "0900"
                preDict["CloseP"] = self.yesPrice
            if aIdx == (len(self.minTimeList) - 1):  #最後一筆資料
                self._drawPriceLine(preDict, aDict, aIdx, True)
                self._drawVolumeLine(aDict, aIdx, True)
            else:  #其它筆資料
                self._drawPriceLine(preDict, aDict, aIdx, False)
                self._drawVolumeLine(aDict, aIdx, False)
            preDict = aDict
            self.lastMinTime = aDict.get("TD")
        if self.crossLineIndex != None:
            self.drawCrossLine(self.crossLineIndex)

    def _reChartVolume(self):
        self.canvas.remove_group(self.instGroup + "volume_curvData")
        for aIdx in range(0, len(self.minTimeList)):
            aDict = self.minTimeList[aIdx]
            self._drawVolumeLine(aDict, aIdx, False)

    def _getPriceColor(self, prePrice, aPrice):
        if aPrice > prePrice:
            return self.UP_COLOR
        elif aPrice < prePrice:
            return self.DOWN_COLOR
        else:
            return self.EQUAL_COLOR

    def _drawPriceLine(self, preDict, aDict, aIdx, isLastFlag):
        groupStr = self.instGroup
        if isLastFlag == True:
            groupStr += "price_lastData"
        else:
            groupStr += "price_curvData"
        instg = InstructionGroup(group=groupStr)
        color = Color()
        color.rgba = self._getPriceColor(preDict.get("CloseP"),
                                         aDict.get("CloseP"))
        instg.add(color)
        if aIdx == 0:
            x1 = self.start_xaxis
        else:
            x1 = self.start_xaxis + (aIdx - 1) * self.xscale
        y1 = self.price_yaxis + (preDict.get("CloseP") -
                                 self.lowestPrice) * self.price_yscale
        x2 = self.start_xaxis + aIdx * self.xscale
        y2 = self.price_yaxis + (aDict.get("CloseP") -
                                 self.lowestPrice) * self.price_yscale
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

    def _drawVolumeLine(self, aDict, aIdx, isLastFlag):
        groupStr = self.instGroup
        if isLastFlag == True:
            groupStr += "volume_lastData"
        else:
            groupStr += "volume_curvData"
        instg = InstructionGroup(group=groupStr)
        color = Color()
        color.rgba = self.VOLUME_COLOR
        instg.add(color)
        x1 = self.start_xaxis + aIdx * self.xscale
        y1 = self.volume_yaxis
        x2 = x1
        y2 = self.volume_yaxis + aDict.get("Vol") * self.volume_yscale
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

    def addData(self, paramMinTimeList):
        """
        添加匯圖之資料,list中之資料為一dict,資料內容如下所示:
        1.'TD': 時間
        2.'OpenP': 開盤價
        3.'HighP': 最高價
        4.'LowP': 最低價
        5.'CloseP': 收盤價
        6.'OpenRefP': 開盤參考價
        7.'Vol': 成交量
        8.'Amt': 成交金額
        9.'PriceFlag': 漲跌停符號
        10.'VolCRate': 成交量換手率
        11.'TtVolume': 成交總量(此欄位暫不使用)
        12.'TtAmount': 成交總金額(此欄位暫不使用)
        """
        preDict = None
        aDict = None
        if self.lastMinTime == None:  #第一次添加資料時
            for aDict in paramMinTimeList:
                aVol = aDict.get("Vol")
                if self.maxVolume == None:
                    self.maxVolume = aVol
                else:
                    if self.maxVolume < aVol:
                        self.maxVolume = aVol
            self._calcVolumeYScale()
            self._drawVolumeCord()
            isFirst = True
            for aIdx in range(0, len(paramMinTimeList)):
                aDict = paramMinTimeList[aIdx]
                aVol = aDict.get("Vol")
                if isFirst == True:
                    isFirst = False
                    preDict = {}
                    preDict["TD"] = "0900"
                    preDict["CloseP"] = self.yesPrice
                    self.maxVolume = aVol
                if aIdx == (len(paramMinTimeList) - 1):  #最後一筆資料
                    self._drawPriceLine(preDict, aDict, aIdx, True)
                    self._drawVolumeLine(aDict, aIdx, True)
                else:  #其它筆資料
                    self._drawPriceLine(preDict, aDict, aIdx, False)
                    self._drawVolumeLine(aDict, aIdx, False)
                preDict = aDict
                self.lastMinTime = aDict.get("TD")
                self.minTimeList.append(aDict)
                if self.maxVolume < aVol:
                    self.maxVolume = aVol
        else:  #非第一次添加資料
            self.canvas.remove_group(self.instGroup + "price_lastData")
            self.canvas.remove_group(self.instGroup + "volume_lastData")
            isFirst = True
            for aIdx in range(0, len(paramMinTimeList)):
                aDict = paramMinTimeList[aIdx]
                aVol = aDict.get("Vol")
                if isFirst == True:
                    isFirst = False
                    if self.lastMinTime == aDict.get("TD"):
                        self.minTimeList.pop(len(self.minTimeList) - 1)
                        dataLength = len(self.minTimeList)
                        if dataLength == 0:
                            preDict = {}
                            preDict["TD"] = "0900"
                            preDict["CloseP"] = self.yesPrice
                        else:
                            preDict = self.minTimeList[dataLength - 1]
                    else:
                        dataLength = len(self.minTimeList)
                        if dataLength == 1:
                            preDict = {}
                            preDict["TD"] = "0900"
                            preDict["CloseP"] = self.yesPrice
                            tmpDict = self.minTimeList[dataLength - 1]
                        else:
                            preDict = self.minTimeList[dataLength - 2]
                            tmpDict = self.minTimeList[dataLength - 1]
                        self._drawPriceLine(
                            preDict, tmpDict, dataLength - 1,
                            False)  #將price_lastData轉為price_curvData
                        self._drawVolumeLine(
                            tmpDict, dataLength - 1,
                            False)  #將volume_lastData轉為volume_curvData
                if self.maxVolume < aVol:
                    self.maxVolume = aVol
                    self._calcVolumeYScale()
                    self._drawVolumeCord()
                    self._reChartVolume()
                dataLength = len(self.minTimeList)
                if aIdx == (len(paramMinTimeList) - 1):  #最後一筆資料
                    self._drawPriceLine(preDict, aDict, dataLength, True)
                    self._drawVolumeLine(aDict, dataLength, True)
                else:  #其它筆資料
                    self._drawPriceLine(preDict, aDict, dataLength, False)
                    self._drawVolumeLine(aDict, dataLength, False)
                preDict = aDict
                self.lastMinTime = aDict.get("TD")
                if self.crossLineIndex != None and self.crossLineIndex == (
                        len(self.minTimeList) - 1):
                    self.crossLineIndex += 1
                self.minTimeList.append(aDict)
        if self.crossLineIndex != None:
            if self.crossLineIndex == (len(self.minTimeList) - 1):
                self.drawCrossLine(len(self.minTimeList) - 1)

    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.col_default_width = 90
            self.infoLayout.size = [90, 64]
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)
        x1 = self.start_xaxis + index * self.xscale
        halfNum = int(self.chartNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.volume_yaxis + self.crossLine_height - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)

        dataDict = self.minTimeList[index]

        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = "時:" + sutil.formatTime(dataDict.get("TD"))

        price = dataDict.get("CloseP")
        self.infoLayout.add_widget(self.info_price)
        self.info_price.text = "價:" + ("{:7.2f}".format(price)).strip()
        self.info_price.color = self._getPriceColor(self.yesPrice, price)

        self.infoLayout.add_widget(self.info_vol)
        self.info_vol.text = "量:" + ("{:13.0f}".format(
            dataDict.get("Vol"))).strip()

    def drawCrossLine(self, aIndex):
        """
        """
        dataNum = len(self.minTimeList)
        if dataNum == 0:
            return
        if aIndex >= dataNum:
            index = dataNum - 1
        elif aIndex < 0:
            index = 0
        else:
            index = aIndex
        self.crossLineIndex = index
        if self.infoFunc == None:
            self._showInfo(index)
        else:
            self.infoFunc(self.minTimeList[index])

        groupStr = self.instGroup + "cross_line"
        self.canvas.remove_group(groupStr)

        instg = InstructionGroup(group=groupStr)

        color = Color()
        color.rgba = self.CROSS_LINE_COLOR
        instg.add(color)
        x1 = self.start_xaxis + index * self.xscale
        y1 = self.volume_yaxis
        x2 = self.start_xaxis + index * self.xscale
        y2 = self.volume_yaxis + self.crossLine_height
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
Пример #4
0
class SCurvGraph(SBaseTech):
    
    def __init__(self, paramDict):

        super().__init__(paramDict)

        self.CORD_INFO_COLOR = paramDict.get("CORD_INFO_COLOR") #座標資訊的文字顏色
        self.DATA_INFO_COLOR = paramDict.get("DATA_INFO_COLOR") #資訊的文字顏色
        self.CURV_COLOR = paramDict.get("CURV_COLOR") #線條顏色
        self.CROSS_LINE_COLOR = paramDict.get("CROSS_LINE_COLOR") #十字線顏色
        self.techType = paramDict.get("TechType") #技術分析類型
        self.isPriceMA = paramDict.get("IsPriceMA") #是否為價格MA

        self.info_time = SLabel(text="") #時間
        self.info_time.color = self.DATA_INFO_COLOR 
        self.info_data = SLabel(text="") #訊息的值
        self.info_data.color = self.DATA_INFO_COLOR

    def _calcDrawInfo(self):
        """
        計算繪圖所需之資訊
        """
        if self.extremeValue[0] > 0:
            self.highestValue = self.extremeValue[0] * 1.01
        elif self.extremeValue[0] < 0:
            self.highestValue = self.extremeValue[0] * 0.99
        else:
            self.highestValue = self.extremeValue[0]
        if self.extremeValue[1] > 0:
            self.lowestValue = self.extremeValue[1] * 0.99
        elif self.extremeValue[0] < 0:
            self.lowestValue = self.extremeValue[1] * 1.01
        else:
            self.lowestValue = self.extremeValue[1]
        diffValue = self.highestValue - self.lowestValue
        if diffValue != 0:
            self.yscale = 1.0 * self.chartSize[1] / diffValue #線圖y軸縮放比例
        else:
            self.yscale = 1
        if self.dispNum <= len(self.dataDict):
            self.dispMax = self.dispNum
        else:
            self.dispMax = len(self.dataDict)

    def getExtremeValue(self):
        """
        取得在某一頁次之最大值及最小值,回傳一list物件,格式如下所示:
        [最大值,最小值]
        """
        if len(self.keyList) == 0:
            return [0, 0]
        maxValue = sys.maxsize * -1 - 1
        minValue = sys.maxsize
        try:
            for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
                aKey = self.keyList[aIdx]
                aValue = self.dataDict.get(aKey)
                if aValue > maxValue:
                    maxValue = aValue
                if aValue < minValue:
                    minValue = aValue
        except:
            pass

        return [maxValue, minValue]

    def charting(self):
        """
        繪圖
        """
        super().charting()
        
        self.canvas.remove_group(self.instGroup + "_lastData")
        self.canvas.remove_group(self.instGroup + "_curvData")
        
        if self.keyList == None or len(self.keyList) == 0: #無資料時,不作任何動作
            return

        isFirst = True
        dispIdx = -1
        for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
            dispIdx += 1
            aKey = self.keyList[aIdx]
            aValue = self.dataDict.get(aKey)
            if isFirst == True:
                isFirst = False
                if aIdx == 0:
                    preValue = (self.highestValue - self.lowestValue) / 2 + self.lowestValue
                else:
                    tmpKey = self.keyList[aIdx - 1]
                    preValue = self.dataDict.get(tmpKey)
            if dispIdx != 0:
                if self.isPriceMA == True:
                    if preValue != 0:
                        self._drawLine(preValue, aValue, dispIdx, False)
                else:
                    self._drawLine(preValue, aValue, dispIdx, False)
            preValue = aValue
            self.lastKey = aKey

    def _drawLine(self, preValue, aValue, dispIdx, isLastFlag):
        """
        繪製曲線
        """
        groupStr = self.instGroup
        if isLastFlag == True:
            groupStr += "_lastData"
        else:
            groupStr += "_curvData"    
        instg = InstructionGroup(group=groupStr)
        color = Color()
        color.rgba = self.CURV_COLOR
        instg.add(color)
        #(self.tickWide + self.tickGap)代表顯示一筆資料,在x軸方向所需的總點數
        x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) - self.backGap
        y1 = self.chartPos[1] + (preValue - self.lowestValue) * self.yscale
        x2 = x1 + (self.tickWide + self.tickGap)
        y2 = self.chartPos[1] + (aValue - self.lowestValue) * self.yscale
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
    
    def addData(self, paramList):
        """
        添加匯圖之資料,paramList為一list物件,list中為一dict物件,格式如下所示:
        {'TD':'時間','Value':'值'}
        """
        for aDict in paramList:
            aKey = aDict.get("TD")
            self.dataDict[aKey] = aDict.get("Value")
        self.keyList = sorted(list(self.dataDict.keys()))
    
    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)
        
        aKey = self.keyList[self.scopeIdx[0] + index]
        aValue = self.dataDict.get(aKey)
        
        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = sutil.formatDateTime(aKey)

        self.infoLayout.add_widget(self.info_data)
        valueStr = None
        if self.formatType == 1:            
            valueStr = ("{:7.2f}".format(aValue)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(aValue)
        else:
            valueStr = str(aValue)
        self.info_data.text = valueStr

        maxLength = len(self.info_time.text)
        if maxLength < len(self.info_data.text):
            maxLength = len(self.info_data.text)
        
        layoutWidth = schartutil.getInfoLayoutWidth(maxLength)
        self.infoLayout.col_default_width = layoutWidth
        self.infoLayout.size = [layoutWidth, 44]

        x1 = self.chartPos[0] + (index + 1) * (self.tickWide + self.tickGap) - self.backGap
        halfNum = int(self.dispNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.chartPos[1] + self.chartSize[1] - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)
        
    def drawCrossLine(self, aIndex):
        """
        繪製十字線
        """
        dataNum = len(self.dataDict)
        if dataNum == 0:
            return
        if aIndex >= self.dispMax:
            index = self.dispMax - 1
        elif aIndex >= self.dispNum:            
            index = self.dispNum - 1
        elif aIndex < 0:
            index = 0
        else:
            index = aIndex
        self.crossLineIndex = index
        if self.infoFunc == None:
            self._showInfo(index)
        else:
            aKey = self.keyList[self.scopeIdx[0] + index]
            aValue = self.dataDict.get(aKey)
            self.infoFunc({"TechType":self.techType, "TD":aKey, "Value":aValue})
        
        if self.isDrawCrossLine == False:
            return
        groupStr = self.instGroup + "cross_line"
        self.canvas.remove_group(groupStr)        

        color = Color()
        color.rgba = self.CROSS_LINE_COLOR
        
        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0] + (index + 1) * (self.tickWide + self.tickGap) - self.backGap
        y1 = self.chartPos[1]
        x2 = x1
        y2 = self.chartPos[1] + self.chartSize[1]
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
        
        aKey = self.keyList[self.scopeIdx[0] + index]
        aValue = self.dataDict.get(aKey)        
        
        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0]
        y1 = self.chartPos[1] + (aValue - self.lowestValue) * self.yscale
        x2 = self.chartPos[0] + self.chartSize[0]
        y2 = y1 
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
Пример #5
0
class SKLineGraph(SBaseTech):
    def __init__(self, paramDict):

        super().__init__(paramDict)

        self.CORD_INFO_COLOR = paramDict.get("CORD_INFO_COLOR")  #座標資訊的文字顏色
        self.DATA_INFO_COLOR = paramDict.get("DATA_INFO_COLOR")  #資訊的文字顏色
        self.KLINE_COLOR = paramDict.get("KLINE_COLOR")  #線條顏色
        self.SOLID_COLOR = paramDict.get("SOLID_COLOR")  #K線中陽線的顏色
        self.VIRTUAL_COLOR = paramDict.get("VIRTUAL_COLOR")  #K線中陰線的顏色
        self.CROSS_LINE_COLOR = paramDict.get("CROSS_LINE_COLOR")  #十字線顏色

        self.info_time = SLabel(text="")  #時間
        self.info_time.color = self.DATA_INFO_COLOR
        self.info_openPrice = SLabel(text="")  #開盤價
        self.info_openPrice.color = self.DATA_INFO_COLOR
        self.info_highPrice = SLabel(text="")  #最高價
        self.info_highPrice.color = self.DATA_INFO_COLOR
        self.info_lowPrice = SLabel(text="")  #最低價
        self.info_lowPrice.color = self.DATA_INFO_COLOR
        self.info_closePrice = SLabel(text="")  #收盤價
        self.info_closePrice.color = self.DATA_INFO_COLOR

    def _calcDrawInfo(self):
        """
        計算繪圖所需之資訊
        """
        self.highestValue = self.extremeValue[0] * 1.01  #畫面顯示之最大值
        self.lowestValue = self.extremeValue[1] * .99  #畫面顯示之最小值
        diffValue = self.highestValue - self.lowestValue
        if diffValue != 0:
            self.yscale = 1.0 * self.chartSize[1] / diffValue  #K線圖y軸縮放比例
        else:
            self.yscale = 1
        if self.dispNum <= len(self.dataDict):
            self.dispMax = self.dispNum
        else:
            self.dispMax = len(self.dataDict)

    def getExtremeValue(self):
        """
        取得當前頁次之最大值及最小值,回傳一list物件,格式如下所示:
        [最大值,最小值]
        """
        if len(self.keyList) == 0:
            return [0, 0]
        maxValue = sys.maxsize * -1 - 1
        minValue = sys.maxsize
        try:
            for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
                aKey = self.keyList[aIdx]
                aDict = self.dataDict.get(aKey)
                if aDict.get("HP") > maxValue:
                    maxValue = aDict.get("HP")
                if aDict.get("LP") < minValue:
                    minValue = aDict.get("LP")
        except:
            pass
        return [maxValue, minValue]

    def charting(self):
        """
        繪圖
        """
        super().charting()

        self.canvas.remove_group(self.instGroup + "_lastData")
        self.canvas.remove_group(self.instGroup + "_curvData")

        if self.keyList == None or len(self.keyList) == 0:  #無資料時,不作任何動作
            return

        dispIdx = -1
        for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
            dispIdx += 1
            aKey = self.keyList[aIdx]
            aDict = self.dataDict.get(aKey)
            self._drawLine(aDict, dispIdx, False)
            self.lastKey = aKey

    def _drawLine(self, aDict, dispIdx, isLastFlag):
        """
        
        """
        groupStr = self.instGroup
        if isLastFlag == True:
            groupStr += "_lastData"
        else:
            groupStr += "_curvData"
        instg = InstructionGroup(group=groupStr)
        color = Color()
        color.rgba = self.KLINE_COLOR
        instg.add(color)
        #(self.tickWide + self.tickGap)代表顯示一筆資料,在x軸方向所需的總點數
        x1 = self.chartPos[0] + (dispIdx + 1) * (self.tickWide +
                                                 self.tickGap) - self.backGap
        y1 = self.chartPos[1] + (aDict.get("HP") -
                                 self.lowestValue) * self.yscale
        x2 = x1
        y2 = self.chartPos[1] + (aDict.get("LP") -
                                 self.lowestValue) * self.yscale
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

        instg = InstructionGroup(group=groupStr)
        color = Color()

        openPrice = aDict.get("OP")
        closePrice = aDict.get("CP")
        if closePrice > openPrice:
            color.rgba = self.SOLID_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1] + (openPrice -
                                     self.lowestValue) * self.yscale
            instg.add(
                Rectangle(pos=(x1, y1),
                          size=(self.tickWide,
                                (closePrice - openPrice) * self.yscale)))
        elif closePrice < openPrice:
            color.rgba = self.VIRTUAL_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1] + (closePrice -
                                     self.lowestValue) * self.yscale
            instg.add(
                Rectangle(pos=(x1, y1),
                          size=(self.tickWide,
                                (openPrice - closePrice) * self.yscale)))
        else:
            color.rgba = self.KLINE_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1] + (closePrice -
                                     self.lowestValue) * self.yscale
            x2 = self.chartPos[0] + (dispIdx + 1) * (self.tickWide +
                                                     self.tickGap)
            y2 = y1
            instg.add(Line(points=(x1, y1, x2, y2), width=1))

        self.canvas.add(instg)

    def addData(self, paramList):
        """
        添加匯圖之資料,paramList為一list物件,list中為一dict物件,格式如下所示:
        {'TD':'時間','OP':'開盤價','HP':'最高價','LP':'最低價','CP':'收盤價','RP':'開盤參考價',
        'VOL':'成交量','AMT':'成交金額','UDF':'漲停跌符號','RT':'換手率'}
        """
        for aDict in paramList:
            aKey = aDict.get("TD")
            self.dataDict[aKey] = aDict
        self.keyList = sorted(list(self.dataDict.keys()))

    def clearData(self):
        super().clearData()

        self.canvas.remove_group(self.instGroup + "_lastData")
        self.canvas.remove_group(self.instGroup + "_curvData")

    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)

        aKey = self.keyList[self.scopeIdx[0] + index]
        aDict = self.dataDict.get(aKey)

        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = sutil.formatDateTime(aKey)

        self.infoLayout.add_widget(self.info_openPrice)
        openPrice = aDict.get("OP")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(openPrice)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(openPrice)
        else:
            valueStr = str(openPrice)
        self.info_openPrice.text = "開:" + valueStr

        self.infoLayout.add_widget(self.info_highPrice)
        highPrice = aDict.get("HP")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(highPrice)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(highPrice)
        else:
            valueStr = str(highPrice)
        self.info_highPrice.text = "高:" + valueStr

        self.infoLayout.add_widget(self.info_lowPrice)
        lowPrice = aDict.get("LP")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(lowPrice)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(lowPrice)
        else:
            valueStr = str(lowPrice)
        self.info_lowPrice.text = "低:" + valueStr

        self.infoLayout.add_widget(self.info_closePrice)
        closePrice = aDict.get("CP")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(closePrice)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(closePrice)
        else:
            valueStr = str(closePrice)
        self.info_closePrice.text = "收:" + valueStr

        maxLength = len(self.info_time.text)
        if maxLength < schartutil.calcCharNum(self.info_openPrice.text):
            maxLength = schartutil.calcCharNum(self.info_openPrice.text)
        if maxLength < schartutil.calcCharNum(self.info_highPrice.text):
            maxLength = schartutil.calcCharNum(self.info_highPrice.text)
        if maxLength < schartutil.calcCharNum(self.info_lowPrice.text):
            maxLength = schartutil.calcCharNum(self.info_lowPrice.text)
        if maxLength < schartutil.calcCharNum(self.info_closePrice.text):
            maxLength = schartutil.calcCharNum(self.info_closePrice.text)

        layoutWidth = schartutil.getInfoLayoutWidth(maxLength)
        self.infoLayout.col_default_width = layoutWidth
        self.infoLayout.size = [layoutWidth, 104]

        x1 = self.chartPos[0] + (index + 1) * (self.tickWide +
                                               self.tickGap) - self.backGap
        halfNum = int(self.dispNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.chartPos[1] + self.chartSize[1] - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)

    def drawCrossLine(self, aIndex):
        """
        """
        dataNum = len(self.dataDict)
        if dataNum == 0:
            return
        if aIndex >= self.dispMax:
            index = self.dispMax - 1
        elif aIndex >= self.dispNum:
            index = self.dispNum - 1
        elif aIndex < 0:
            index = 0
        else:
            index = aIndex
        self.crossLineIndex = index
        if self.infoFunc == None:
            self._showInfo(index)
        else:
            aKey = self.keyList[self.scopeIdx[0] + index]
            aDict = self.dataDict.get(aKey)
            refDict = {}
            for aKey in aDict.keys():
                refDict[aKey] = aDict.get(aKey)
            preIndex = self.scopeIdx[0] + index - 1
            if preIndex < 0:
                refDict["UD"] = 0
            else:
                aKey = self.keyList[preIndex]
                preDict = self.dataDict.get(aKey)
                refDict["UD"] = aDict.get("CP") - preDict.get("CP")
            self.infoFunc(refDict)

        if self.isDrawCrossLine == False:
            return
        groupStr = self.instGroup + "cross_line"
        self.canvas.remove_group(groupStr)

        color = Color()
        color.rgba = self.CROSS_LINE_COLOR

        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0] + (index + 1) * (self.tickWide +
                                               self.tickGap) - self.backGap
        y1 = self.chartPos[1]
        x2 = x1
        y2 = self.chartPos[1] + self.chartSize[1]
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

        aKey = self.keyList[self.scopeIdx[0] + index]
        aDict = self.dataDict.get(aKey)

        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0]
        y1 = self.chartPos[1] + (aDict.get("CP") -
                                 self.lowestValue) * self.yscale
        x2 = self.chartPos[0] + self.chartSize[0]
        y2 = y1
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
Пример #6
0
class SVolBarGraph(SBaseTech):
    def __init__(self, paramDict):

        super().__init__(paramDict)

        self.CORD_INFO_COLOR = paramDict.get("CORD_INFO_COLOR")  #座標資訊的文字顏色
        self.DATA_INFO_COLOR = paramDict.get("DATA_INFO_COLOR")  #資訊的文字顏色
        self.UP_COLOR = paramDict.get("UP_COLOR")  #上漲時條狀圖的顏色
        self.DOWN_COLOR = paramDict.get("DOWN_COLOR")  #下跌時條狀圖的顏色
        self.EQUAL_COLOR = paramDict.get("EQUAL_COLOR")  #持平時條狀圖的顏色
        self.CROSS_LINE_COLOR = paramDict.get("CROSS_LINE_COLOR")  #十字線顏色
        self.techType = paramDict.get("TechType")  #技術分析類型

        self.info_time = SLabel(text="")  #時間
        self.info_time.color = self.DATA_INFO_COLOR
        self.info_vol = SLabel(text="")  #成交量
        self.info_vol.color = self.DATA_INFO_COLOR

    def _calcDrawInfo(self):
        self.highestValue = self.extremeValue[0] * 1.01  #畫面顯示之最大值
        self.lowestValue = 0  #畫面顯示之最小值
        diffValue = self.highestValue - self.lowestValue
        if diffValue != 0:
            self.yscale = 1.0 * self.chartSize[1] / (
                self.highestValue - self.lowestValue)  #線圖y軸縮放比例
        else:
            self.yscale = 1
        if self.dispNum <= len(self.dataDict):
            self.dispMax = self.dispNum
        else:
            self.dispMax = len(self.dataDict)

    def getExtremeValue(self):
        """
        取得當前頁次之最大值及最小值,回傳一list物件,格式如下所示:
        [最大值,最小值]
        """
        if len(self.keyList) == 0:
            return [0, 0]
        maxValue = sys.maxsize * -1 - 1
        minValue = 0
        try:
            for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
                aKey = self.keyList[aIdx]
                aDict = self.dataDict.get(aKey)
                if aDict.get("VOL") > maxValue:
                    maxValue = aDict.get("VOL")
        except:
            pass

        return [maxValue, minValue]

    def charting(self):
        """
        繪圖
        """
        super().charting()

        self.canvas.remove_group(self.instGroup + "_lastData")
        self.canvas.remove_group(self.instGroup + "_curvData")

        if self.keyList == None or len(self.keyList) == 0:  #無資料時,不作任何動作
            return

        isFirst = True
        dispIdx = -1
        for aIdx in range(self.scopeIdx[0], self.scopeIdx[1] + 1):
            dispIdx += 1
            aKey = self.keyList[aIdx]
            aDict = self.dataDict.get(aKey)
            if isFirst == True:
                isFirst = False
                if aIdx == 0:
                    preClosePrice = 0
                else:
                    tmpKey = self.keyList[aIdx - 1]
                    preClosePrice = self.dataDict.get(tmpKey).get("CP")
            self._drawLine(preClosePrice, aDict, dispIdx, False)
            preClosePrice = aDict.get("CP")
            self.lastKey = aKey

    def _drawLine(self, preClose, aDict, dispIdx, isLastFlag):
        """
        
        """
        groupStr = self.instGroup
        if isLastFlag == True:
            groupStr += "_lastData"
        else:
            groupStr += "_curvData"

        instg = InstructionGroup(group=groupStr)
        color = Color()

        volume = aDict.get("VOL")

        closePrice = aDict.get("CP")
        if closePrice > preClose:
            color.rgba = self.UP_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1]
            instg.add(
                Rectangle(pos=(x1, y1),
                          size=(self.tickWide,
                                (volume - self.lowestValue) * self.yscale)))
        elif closePrice < preClose:
            color.rgba = self.DOWN_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1]
            instg.add(
                Rectangle(pos=(x1, y1),
                          size=(self.tickWide,
                                (volume - self.lowestValue) * self.yscale)))
        else:
            color.rgba = self.EQUAL_COLOR
            instg.add(color)
            x1 = self.chartPos[0] + dispIdx * (self.tickWide +
                                               self.tickGap) + self.tickGap
            y1 = self.chartPos[1]
            instg.add(
                Rectangle(pos=(x1, y1),
                          size=(self.tickWide,
                                (volume - self.lowestValue) * self.yscale)))

        self.canvas.add(instg)

    def addData(self, paramList):
        """
        添加匯圖之資料,paramList為一list物件,list中為一dict物件,格式如下所示:
        {'TD':'時間','CP':'收盤價','VOL':'成交量'}
        """
        for aDict in paramList:
            aKey = aDict.get("TD")
            self.dataDict[aKey] = aDict
        self.keyList = sorted(list(self.dataDict.keys()))

    def _showInfo(self, index):
        if self.infoLayout == None:
            self.infoLayout = SInfoLayout(cols=1)
            self.infoLayout.row_force_default = True
            self.infoLayout.row_default_height = 20
            self.infoLayout.col_force_default = True
            self.infoLayout.padding = [2, 1, 2, 1]
            self.infoLayout.size_hint = (None, None)
        else:
            self.infoLayout.clear_widgets()
        if self.infoLayout.parent == None:
            self.layout.add_widget(self.infoLayout)

        aKey = self.keyList[self.scopeIdx[0] + index]
        aDict = self.dataDict.get(aKey)

        self.infoLayout.add_widget(self.info_time)
        self.info_time.text = sutil.formatDateTime(aKey)

        self.infoLayout.add_widget(self.info_vol)
        volume = aDict.get("VOL")
        valueStr = None
        if self.formatType == 1:
            valueStr = ("{:7.2f}".format(volume)).strip()
        elif self.formatType == 2:
            valueStr = "${:,}".format(volume)
        else:
            valueStr = str(volume)
        self.info_vol.text = valueStr

        maxLength = len(self.info_time.text)
        if maxLength < schartutil.calcCharNum(self.info_vol.text):
            maxLength = schartutil.calcCharNum(self.info_vol.text)

        layoutWidth = schartutil.getInfoLayoutWidth(maxLength)
        self.infoLayout.col_default_width = layoutWidth
        self.infoLayout.size = [layoutWidth, 44]

        x1 = self.chartPos[0] + (index + 1) * (self.tickWide +
                                               self.tickGap) - self.backGap
        halfNum = int(self.dispNum / 2)
        if index > halfNum:
            pos_x = x1 - self.infoLayout.width
        else:
            pos_x = x1 + 5
        pos_y = self.chartPos[1] + self.chartSize[1] - self.infoLayout.height
        self.infoLayout.pos = (pos_x, pos_y)

    def drawCrossLine(self, aIndex):
        """
        """
        dataNum = len(self.dataDict)
        if dataNum == 0:
            return
        if aIndex >= self.dispMax:
            index = self.dispMax - 1
        elif aIndex >= self.dispNum:
            index = self.dispNum - 1
        elif aIndex < 0:
            index = 0
        else:
            index = aIndex
        self.crossLineIndex = index
        if self.infoFunc == None:
            self._showInfo(index)
        else:
            aKey = self.keyList[self.scopeIdx[0] + index]
            aDict = self.dataDict.get(aKey)
            refDict = {}
            for aKey in aDict.keys():
                refDict[aKey] = aDict.get(aKey)
            refDict["TechType"] = self.techType
            self.infoFunc(refDict)

        if self.isDrawCrossLine == False:
            return
        groupStr = self.instGroup + "cross_line"
        self.canvas.remove_group(groupStr)

        color = Color()
        color.rgba = self.CROSS_LINE_COLOR

        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0] + (index + 1) * (self.tickWide +
                                               self.tickGap) - self.backGap
        y1 = self.chartPos[1]
        x2 = x1
        y2 = self.chartPos[1] + self.chartSize[1]
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

        aKey = self.keyList[self.scopeIdx[0] + index]
        aDict = self.dataDict.get(aKey)

        instg = InstructionGroup(group=groupStr)
        instg.add(color)
        x1 = self.chartPos[0]
        y1 = self.chartPos[1] + (aDict.get("VOL") -
                                 self.lowestValue) * self.yscale
        x2 = self.chartPos[0] + self.chartSize[0]
        y2 = y1
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
Пример #7
0
    def mousePos(self, *args):
        if len(args) >= 2:
            key = None
            xcord = None
            if len(self.profitPerNumDict) != 0 and len(self.xcordDict) != 0:
                for xkey in self.xcordDict.keys():
                    xcord = self.xcordDict.get(xkey)
                    if args[1][0] < (xcord + 0.5) and args[1][0] < (xcord - 0.5):
                        key = int(xkey)
                        break
                if key == None:
                    self.clearCrossLineAndInfo()
                    return
                aNum = self.profitPerNumDict.get(str(key))
                if aNum == None:
                    self.clearCrossLineAndInfo()
                    return
                                
                self.drawCrossLine(str(key))

                if self.infoLayout == None:
                    self.infoLayout = SInfoLayout(cols=1)
                    self.infoLayout.row_force_default = True
                    self.infoLayout.row_default_height = 20
                    self.infoLayout.col_force_default = True
                    self.infoLayout.col_default_width = 110
                    self.infoLayout.padding = [2, 1, 2, 1]
                    self.infoLayout.size_hint = (None, None)
                else:
                    self.infoLayout.clear_widgets()
                if self.infoLayout.parent == None:
                    self.add_widget(self.infoLayout)
                index = key - self.min_tickNum
                center_pos = int(self.pillarPoint / 2)
                if key == 0:
                    shift_xpos = self.ycordWidth
                elif key > 0:
                    shift_xpos = self.ycordWidth * 2
                else:
                    shift_xpos = 0                
                x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos)
                if (self.width - x1) < (self.infoLayout.width + self.shift_right):
                    pos_x = x1 - self.infoLayout.width
                else:
                    pos_x = x1 + 5
                y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) 
                if (self.height - y1) < (self.infoLayout.height + self.shift_top):
                    pos_y = y1 - self.infoLayout.height
                else:
                    pos_y = y1 + 5
                self.infoLayout.pos = (pos_x, pos_y)

                self.info_tradeNum = SLabel(text="") #交易次數
                self.info_tradeNum.color = self.TRADE_INFO_FGCOLOR 
                self.info_profitPer = SLabel(text="") #獲利率
                self.info_profitPer.color = self.TRADE_INFO_FGCOLOR 
                    
                rowNum = 1                    
                self.infoLayout.add_widget(self.info_profitPer)
                self.info_profitPer.text = "獲利率:" + str(key) + "%"
                    
                rowNum += 1
                self.infoLayout.add_widget(self.info_tradeNum)
                self.info_tradeNum.text = "交易次數:" + str(aNum)
                        
                self.infoLayout.size = (110, rowNum * 20)
Пример #8
0
class STradeGraph(FloatLayout):
    
    isFocus = True
    infoLayout = None
    profitPerNumDict = {}
    xcordDict = {}
    
    def __init__(self, paramDict, **kwargs):
        super(STradeGraph, self).__init__(**kwargs)
        
        self.paramDict = paramDict
        self.btmenu = self.paramDict.get(CONSTS.S_BTMENU)
        self.dataList = self.paramDict.get("dataList")
        # 1001-Start: 計算最大及最小獲利率
        self.min_profitPer = 0
        self.max_profitPer = 0
        tmpProfitPer = None
        if self.dataList != None and len(self.dataList) != 0:
            for profitPer in self.dataList:
                if profitPer < 0:
                    tmpProfitPer = math.floor(profitPer)
                else:
                    tmpProfitPer = math.ceil(profitPer)
                if tmpProfitPer > self.max_profitPer:
                    self.max_profitPer = tmpProfitPer
                if tmpProfitPer < self.min_profitPer:
                    self.min_profitPer = tmpProfitPer
        self.min_profitPer = int(self.min_profitPer)
        self.max_profitPer = int(self.max_profitPer)
        # 1001-End.
        self.maxNum = 5
        self.yscale = 1

        tradeGraphDict = sutil.getDictFromFile(os.path.join(os.path.dirname(__file__), ".." + os.sep + "conf" + os.sep + "trade_graph.ini"))
        self.shift_left = int(tradeGraphDict.get("SHIFT_LEFT"))
        self.shift_right = int(tradeGraphDict.get("SHIFT_RIGHT"))
        self.shift_bottom = int(tradeGraphDict.get("SHIFT_BOTTOM"))
        self.shift_top = int(tradeGraphDict.get("SHIFT_TOP"))
        self.ycordWidth = int(tradeGraphDict.get("YCORD_WIDTH"))
        self.pillarPoint = int(tradeGraphDict.get("PILLAR_POINT"))
        self.pillarGapPoint = int(tradeGraphDict.get("PILLAR_GAP_POINT"))
        self.pillarSumPoint = self.pillarPoint + self.pillarGapPoint
        self.FRAME_COLOR = colorHex(tradeGraphDict.get("FRAME_COLOR"))
        self.GRID_COLOR = colorHex(tradeGraphDict.get("GRID_COLOR"))
        self.CORD_INFO_COLOR = colorHex(tradeGraphDict.get("CORD_INFO_COLOR"))
        self.CROSS_LINE_COLOR = colorHex(tradeGraphDict.get("CROSS_LINE_COLOR"))
        self.TRADE_INFO_FGCOLOR = colorHex(tradeGraphDict.get("TRADE_INFO_FGCOLOR"))

        self.info_tradeNum = SLabel(text="") #交易次數
        self.info_tradeNum.color = self.TRADE_INFO_FGCOLOR 
        self.info_profitPer = SLabel(text="") #獲利率
        self.info_profitPer.color = self.TRADE_INFO_FGCOLOR 

        self.bind(pos=self.charting)
        self.bind(size=self.charting)
        Window.bind(mouse_pos=self.mousePos)
        
    def calcMaxTick(self):
        """
        依據容器的寬度及傳入之數據,計算圖形可畫出之最大及最小的tick值
        """
        
        all_tickNum = (int)((self.width - self.ycordWidth * 2 - self.shift_left - self.shift_right) / self.pillarSumPoint)
        half_tickNum = (int)((all_tickNum - 1) / 2)
        all_tickNum = half_tickNum * 2
        self.min_tickNum = half_tickNum * -1
        self.max_tickNum = half_tickNum
        
        if self.min_profitPer < self.min_tickNum and self.max_profitPer < self.max_tickNum:
            diff = self.max_profitPer - self.min_profitPer
            if diff >= all_tickNum: 
                self.max_tickNum = self.max_profitPer
                self.min_tickNum = (half_tickNum * 2 - self.max_tickNum) * -1
            else:
                shift_num = self.min_tickNum - self.min_profitPer
                self.max_tickNum = self.max_tickNum - shift_num
                self.min_tickNum = self.min_tickNum - shift_num
        elif self.min_profitPer > self.min_tickNum and self.max_profitPer > self.max_tickNum:
            diff = self.max_profitPer - self.min_profitPer
            if diff >= all_tickNum: 
                self.min_tickNum = self.min_profitPer
                self.max_tickNum = half_tickNum * 2 + self.min_profitPer
            else:
                shift_num = self.max_profitPer - self.max_tickNum
                self.max_tickNum = self.max_tickNum + shift_num
                self.min_tickNum = self.min_tickNum + shift_num

        self.max_tickNum = int(self.max_tickNum)
        self.min_tickNum = int(self.min_tickNum)

    def drawNoDataGraph(self):
        """
        繪製一個沒有數據之圖形
        """
        self.calcMaxTick()
        self.drawCordFrame()
        self.yscale = (self.height - self.shift_bottom - self.shift_top) / self.maxNum
        self.drawCordInfo()
        
    def charting(self, *args):
        """
        繪圖
        """
        self.canvas.clear()

        if self.dataList == None or len(self.dataList) == 0:
            self.drawNoDataGraph()
            return

        self.calcMaxTick()
        self.drawCordFrame()
        
        self.profitPerNumDict.clear()
        self.maxNum = 5
        tmpProfitPer = None
        aNum = None
        for profitPer in self.dataList:
            if profitPer < 0:
                tmpProfitPer = math.floor(profitPer)
                if tmpProfitPer < self.min_tickNum:
                    tmpProfitPer = self.min_tickNum
            else:
                tmpProfitPer = math.ceil(profitPer)
                if tmpProfitPer > self.max_tickNum:
                    tmpProfitPer = self.max_tickNum
                
            tmpProfitPer = int(tmpProfitPer)
            aNum = self.profitPerNumDict.get(str(tmpProfitPer))
            if aNum == None:
                aNum = 0
            aNum += 1
            self.profitPerNumDict[str(tmpProfitPer)] = aNum
            if aNum > self.maxNum:
                self.maxNum = aNum

        self.yscale = (self.height - self.shift_bottom - self.shift_top) / self.maxNum
        
        self.drawCordInfo()
        
        index = None
        shift_xpos = None
        center_pos = int(self.pillarPoint / 2)
        for i in range(self.min_tickNum, self.max_tickNum + 1):
            if i == 0:
                shift_xpos = self.ycordWidth
            elif i > 0:
                shift_xpos = self.ycordWidth * 2
            else:
                shift_xpos = 0
            index = i - self.min_tickNum
            aNum = self.profitPerNumDict.get(str(i))
            if aNum != None:
                lineColor = Color()
                lineColor.rgba = self.GRID_COLOR                
                
                instg = InstructionGroup(group="data")
                instg.add(lineColor)
                
                x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos)
                y1 = int(self.pos[1] + self.shift_bottom)
                x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos)
                y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
                instg.add(Line(points=(x1, y1, x2, y2), width=1))
                self.canvas.add(instg)
                
                instg = InstructionGroup(group="data")
                instg.add(lineColor)
                
                x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos)
                y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
                x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos)
                y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
                instg.add(Line(points=(x1, y1, x2, y2), width=1))
                self.canvas.add(instg)
                
                instg = InstructionGroup(group="data")
                instg.add(lineColor)
                
                x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos)
                y1 = int(self.pos[1] + self.shift_bottom)
                x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos)
                y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
                instg.add(Line(points=(x1, y1, x2, y2), width=1))
                self.canvas.add(instg)

            x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos)
            self.xcordDict[str(i)] = x1
    def drawCordFrame(self):
        
        # 畫一條橫線
        instg = InstructionGroup(group="frame")
        frameColor = Color()
        frameColor.rgba = self.FRAME_COLOR
        instg.add(frameColor)
        x1 = int(self.pos[0] + self.shift_left)
        y1 = int(self.pos[1] + self.shift_bottom)
        x2 = int(self.pos[0] + self.width - self.shift_right)
        y2 = int(self.pos[1] + self.shift_bottom)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))        
        self.canvas.add(instg)
        
        # 畫一條豎線
        instg = InstructionGroup(group="frame")
        instg.add(frameColor)
        center_pos = int(self.pillarPoint / 2)
        self.center_xpos = int(self.pos[0] + self.shift_left + (self.min_tickNum * -1) * self.pillarSumPoint + self.ycordWidth + center_pos)
        x1 = self.center_xpos
        y1 = int(self.pos[1] + self.shift_bottom)
        x2 = self.center_xpos
        y2 = int(self.pos[1] + self.height - self.shift_top)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

    def drawCordInfo(self):
        
        # 100-Start: 標示y軸資訊 
        
        initStepUp = 1
        if self.maxNum < 8:
            initStepUp = 1
        elif self.maxNum < 10:
            initStepUp = 2
        else:
            initStepUp = int(self.maxNum / 5)
        
        x0 = self.pos[0] + ((self.width - self.shift_left - self.shift_right) / 2) + self.shift_left - 30
        y0 = self.pos[1] + self.height - self.shift_top + 5           
        alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None))
        alabel.width = 60
        alabel.height = 20        
        alabel.text = "(X軸:獲利率,Y軸:交易次數)"
        alabel.color = self.CORD_INFO_COLOR
        self.add_widget(alabel)
            
        frameColor = Color()
        frameColor.rgba = self.FRAME_COLOR
        stepUp = initStepUp
        while(stepUp <= self.maxNum):
            instg = InstructionGroup(group="frame")            
            instg.add(frameColor)            
            x1 = self.center_xpos - 5
            y1 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale)
            x2 = self.center_xpos
            y2 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale)
            instg.add(Line(points=(x1, y1, x2, y2), width=1))        
            self.canvas.add(instg)
            
            x0 = self.center_xpos - self.ycordWidth
            y0 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale) - 10
            alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None))
            alabel.width = 36
            alabel.height = 20
            alabel.text = str(stepUp)
            alabel.color = self.CORD_INFO_COLOR
            self.add_widget(alabel)
            stepUp += initStepUp
        # 100-End.
        
        # 200-Start: 標示x軸資訊 
        center_pos = int(self.pillarPoint / 2)
        remainder = None
        for i in range(self.min_tickNum, self.max_tickNum + 1):
            remainder = i % 10
            if remainder != 0 and i != -1 and i != 0 and i != 1 and i != self.min_tickNum and i != self.max_tickNum:
                continue
            index = i - self.min_tickNum
            if i >= 0:
                tmp = self.max_tickNum - i
                if tmp <= 8 and i != self.max_tickNum:
                    continue
                if i == 0:
                    shift_xpos = self.ycordWidth
                else:
                    shift_xpos = self.ycordWidth * 2
            else:
                if index <= 8 and i != self.min_tickNum:
                    continue
                shift_xpos = 0            
            instg = InstructionGroup(group="frame")            
            instg.add(frameColor)            
            x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos)
            y1 = int(self.pos[1] + self.shift_bottom)
            x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos)
            y2 = int(self.pos[1] + self.shift_bottom - 5)
            instg.add(Line(points=(x1, y1, x2, y2), width=1))        
            self.canvas.add(instg)
            
            x0 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos - 18)
            y0 = int(self.pos[1] + self.shift_bottom) - 25
            alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None))
            alabel.width = 36
            alabel.height = 20
            if i == self.min_tickNum:
                alabel.text = "<=" + str(i) + "%"
            elif i == self.max_tickNum:
                alabel.text = ">=" + str(i) + "%"
            else:
                alabel.text = str(i) + "%"
            alabel.color = self.CORD_INFO_COLOR
            self.add_widget(alabel)
        # 200-End.

    def drawCrossLine(self, key):
        if len(self.profitPerNumDict) == 0:
            return
        
        aNum = self.profitPerNumDict.get(key)
        if aNum == None:
            return
        
        keyInt = int(key)
        
        index = keyInt - self.min_tickNum
        if keyInt == 0:
            shift_xpos = self.ycordWidth
        elif keyInt > 0:
            shift_xpos = self.ycordWidth * 2
        else:
            shift_xpos = 0
        
        color = Color()
        color.rgba = self.CROSS_LINE_COLOR

        self.canvas.remove_group("cross_line")
        
        center_pos = int(self.pillarPoint / 2)
        instg = InstructionGroup(group="cross_line")
        instg.add(color)
        x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos)
        y1 = int(self.pos[1] + self.shift_bottom)
        x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos)
        y2 = int(self.pos[1] + self.shift_bottom + self.maxNum * self.yscale)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)
                
        instg = InstructionGroup(group="cross_line")
        instg.add(color)
        x1 = self.pos[0] + self.shift_left
        y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
        x2 = self.pos[0] + self.width - self.shift_right
        y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))        
        self.canvas.add(instg)

    def clearCrossLineAndInfo(self):
        self.canvas.remove_group("cross_line")
        if self.infoLayout != None:
            if self.infoLayout.parent != None:
                self.remove_widget(self.infoLayout)   

    def mousePos(self, *args):
        if len(args) >= 2:
            key = None
            xcord = None
            if len(self.profitPerNumDict) != 0 and len(self.xcordDict) != 0:
                for xkey in self.xcordDict.keys():
                    xcord = self.xcordDict.get(xkey)
                    if args[1][0] < (xcord + 0.5) and args[1][0] < (xcord - 0.5):
                        key = int(xkey)
                        break
                if key == None:
                    self.clearCrossLineAndInfo()
                    return
                aNum = self.profitPerNumDict.get(str(key))
                if aNum == None:
                    self.clearCrossLineAndInfo()
                    return
                                
                self.drawCrossLine(str(key))

                if self.infoLayout == None:
                    self.infoLayout = SInfoLayout(cols=1)
                    self.infoLayout.row_force_default = True
                    self.infoLayout.row_default_height = 20
                    self.infoLayout.col_force_default = True
                    self.infoLayout.col_default_width = 110
                    self.infoLayout.padding = [2, 1, 2, 1]
                    self.infoLayout.size_hint = (None, None)
                else:
                    self.infoLayout.clear_widgets()
                if self.infoLayout.parent == None:
                    self.add_widget(self.infoLayout)
                index = key - self.min_tickNum
                center_pos = int(self.pillarPoint / 2)
                if key == 0:
                    shift_xpos = self.ycordWidth
                elif key > 0:
                    shift_xpos = self.ycordWidth * 2
                else:
                    shift_xpos = 0                
                x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos)
                if (self.width - x1) < (self.infoLayout.width + self.shift_right):
                    pos_x = x1 - self.infoLayout.width
                else:
                    pos_x = x1 + 5
                y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) 
                if (self.height - y1) < (self.infoLayout.height + self.shift_top):
                    pos_y = y1 - self.infoLayout.height
                else:
                    pos_y = y1 + 5
                self.infoLayout.pos = (pos_x, pos_y)

                self.info_tradeNum = SLabel(text="") #交易次數
                self.info_tradeNum.color = self.TRADE_INFO_FGCOLOR 
                self.info_profitPer = SLabel(text="") #獲利率
                self.info_profitPer.color = self.TRADE_INFO_FGCOLOR 
                    
                rowNum = 1                    
                self.infoLayout.add_widget(self.info_profitPer)
                self.info_profitPer.text = "獲利率:" + str(key) + "%"
                    
                rowNum += 1
                self.infoLayout.add_widget(self.info_tradeNum)
                self.info_tradeNum.text = "交易次數:" + str(aNum)
                        
                self.infoLayout.size = (110, rowNum * 20)
Пример #9
0
    def mousePos(self, *args):
        if len(args) >= 2:
            if self.dataList != None and len(self.dataList) != 0:
                index = int(
                    (args[1][0] - self.pos[0] - self.shift_left) / self.xscale)
                if index < len(self.dataList) and index >= 0:
                    data = self.dataList[index]
                    dateStr = str(data.get("date"))
                    timeStr = str(data.get("time"))
                    price = data.get("price")
                    self.drawCrossLine(index)

                    if self.infoLayout == None:
                        self.infoLayout = SInfoLayout(cols=1)
                        self.infoLayout.row_force_default = True
                        self.infoLayout.row_default_height = 20
                        self.infoLayout.col_force_default = True
                        self.infoLayout.col_default_width = 110
                        self.infoLayout.padding = [2, 1, 2, 1]
                        self.infoLayout.size_hint = (None, None)
                    else:
                        self.infoLayout.clear_widgets()
                    if self.infoLayout.parent == None:
                        self.add_widget(self.infoLayout)
                    x1 = int(self.pos[0] + self.shift_left +
                             index * self.xscale)
                    if (self.width - x1) < (self.infoLayout.width +
                                            self.shift_right):
                        pos_x = x1 - self.infoLayout.width
                    else:
                        pos_x = x1 + 5
                    y1 = int(self.pos[1] + self.shift_bottom +
                             (price - self.min_price) * self.yscale)
                    if (self.height - y1) < (self.infoLayout.height +
                                             self.shift_top):
                        pos_y = y1 - self.infoLayout.height
                    else:
                        pos_y = y1 + 5
                    self.infoLayout.pos = (pos_x, pos_y)

                    rowNum = 1
                    self.infoLayout.add_widget(self.info_date)
                    self.info_date.text = sutil.formatDate(dateStr)

                    if timeStr != "" and timeStr != "0":
                        rowNum += 1
                        self.infoLayout.add_widget(self.info_time)
                        self.info_time.text = sutil.formatTime(timeStr)

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_price)
                    self.info_price.text = "價:" + (
                        "{:7.2f}".format(price)).strip()

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_vol)
                    self.info_vol.text = "量:" + ("{:13.0f}".format(
                        data.get("vol"))).strip()

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_amt)
                    self.info_amt.text = "金:" + ("{:13.0f}".format(
                        data.get("amt"))).strip()

                    bs = data.get("bs")
                    bsprice = data.get("bsprice")
                    if bs != "":
                        rowNum += 1
                        self.infoLayout.add_widget(self.info_bs)
                        self.info_bs.text = bs + ":" + (
                            "{:7.2f}".format(bsprice)).strip()

                    self.infoLayout.size = (110, rowNum * 20)
                else:
                    self.canvas.remove_group("cross_line")
                    if self.infoLayout != None:
                        if self.infoLayout.parent != None:
                            self.remove_widget(self.infoLayout)
Пример #10
0
class STrendGraph(FloatLayout):

    isFocus = True
    infoLayout = None
    rectGridList = None

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

        with self.canvas:
            Color(0, 20 / 255, 45 / 255)
            Rectangle(pos=self.pos, size=self.size)

        self.paramDict = paramDict
        self.btmenu = self.paramDict.get(CONSTS.S_BTMENU)
        self.tickNum = self.paramDict.get("ticknum")
        self.dataList = self.paramDict.get("datalist")
        if self.tickNum == 600:
            self.xgrid_num = 100
        elif self.tickNum == 500:
            self.xgrid_num = 90
        elif self.tickNum == 400:
            self.xgrid_num = 70
        elif self.tickNum == 300:
            self.xgrid_num = 50
        elif self.tickNum == 200:
            self.xgrid_num = 40
        else:
            self.xgrid_num = 30

        self.crossLineXIndex = -1
        self.crossLineYIndex = -1

        trendGraphDict = sutil.getDictFromFile(
            os.path.join(os.path.dirname(__file__),
                         ".." + os.sep + "conf" + os.sep + "trend_graph.ini"))
        self.shift_left = int(trendGraphDict.get("SHIFT_LEFT"))
        self.shift_right = int(trendGraphDict.get("SHIFT_RIGHT"))
        self.shift_bottom = int(trendGraphDict.get("SHIFT_BOTTOM"))
        self.shift_top = int(trendGraphDict.get("SHIFT_TOP"))
        self.CORD_INFO_COLOR = colorHex(trendGraphDict.get("CORD_INFO_COLOR"))
        self.UP_COLOR = colorHex(trendGraphDict.get("UP_COLOR"))
        self.DOWN_COLOR = colorHex(trendGraphDict.get("DOWN_COLOR"))
        self.EQUAL_COLOR = colorHex(trendGraphDict.get("EQUAL_COLOR"))
        self.VOLUME_COLOR = colorHex(trendGraphDict.get("VOLUME_COLOR"))
        self.FRAME_COLOR = colorHex(trendGraphDict.get("FRAME_COLOR"))
        self.GRID_COLOR = colorHex(trendGraphDict.get("GRID_COLOR"))
        self.CROSS_LINE_COLOR = colorHex(
            trendGraphDict.get("CROSS_LINE_COLOR"))
        self.TRADEB_SIG_COLOR = colorHex(
            trendGraphDict.get("TRADEB_SIG_COLOR"))
        self.TRADES_SIG_COLOR = colorHex(
            trendGraphDict.get("TRADES_SIG_COLOR"))
        self.TRADE_INFO_FGCOLOR = colorHex(
            trendGraphDict.get("TRADE_INFO_FGCOLOR"))

        self.info_date = SLabel(text="")  #日期
        self.info_date.color = self.TRADE_INFO_FGCOLOR
        self.info_time = SLabel(text="")  #時間
        self.info_time.color = self.TRADE_INFO_FGCOLOR
        self.info_price = SLabel(text="")  #成交價
        self.info_price.color = self.TRADE_INFO_FGCOLOR
        self.info_vol = SLabel(text="")  #成交量
        self.info_vol.color = self.TRADE_INFO_FGCOLOR
        self.info_amt = SLabel(text="")  #金額
        self.info_amt.color = self.TRADE_INFO_FGCOLOR
        self.info_bs = SLabel(text="")  #買賣訊號及買(賣)價
        self.info_bs.color = self.TRADE_INFO_FGCOLOR

        self.calcMaxTick()

        self.bind(pos=self.charting)
        self.bind(size=self.charting)
        Window.bind(mouse_pos=self.mousePos)

    def calcMaxTick(self):
        self.max_tickNum = 0
        if self.dataList == None:
            self.max_tickNum = self.tickNum
        elif self.tickNum > len(self.dataList):
            self.max_tickNum = self.tickNum
        else:
            self.max_tickNum = len(self.dataList)

    def charting(self, *args):
        self.canvas.clear()

        if self.dataList == None or len(self.dataList) == 0:
            return

        self.max_price_s = -1
        self.min_price_s = sys.maxsize
        self.max_volume = 0

        for data in self.dataList:
            price = data.get("price")
            if price > self.max_price_s:
                self.max_price_s = price
            if price < self.min_price_s:
                self.min_price_s = price
            vol = data.get("vol")
            if vol > self.max_volume:
                self.max_volume = vol

        diffMaxMin = (self.max_price_s - self.min_price_s) / 100.0
        self.max_price = self.max_price_s + diffMaxMin * 6
        self.min_price = self.min_price_s - diffMaxMin * 14
        self.xscale = 1.0 * (self.width - self.shift_left -
                             self.shift_right) / self.max_tickNum
        self.yscale = 1.0 * (self.height - self.shift_bottom - self.shift_top
                             ) / (self.max_price - self.min_price)
        self.vscale = self.yscale * (self.min_price_s -
                                     self.min_price) * .8 / self.max_volume

        self.drawFrameGrid()

        curIndex = preIndex = -1
        prePrice = 0

        x1 = 0
        y1 = 0
        x2 = 0
        y2 = 0

        for data in self.dataList:
            curIndex += 1
            if curIndex == 0:
                self.drawXCoordinateInfo(0)
                preIndex = curIndex
                prePrice = data.get("price")
                self.drawVolumeGraph(data, 0)
                self.addBSPoint(0)
                continue

            instg = InstructionGroup(group="data")
            curPrice = data.get("price")
            color = self.getLineColor(prePrice, curPrice)
            instg.add(color)

            x1 = int(self.pos[0] + self.shift_left + preIndex * self.xscale)
            y1 = int(self.pos[1] + self.shift_bottom +
                     (prePrice - self.min_price) * self.yscale)
            x2 = int(self.pos[0] + self.shift_left + curIndex * self.xscale)
            y2 = int(self.pos[1] + self.shift_bottom +
                     (curPrice - self.min_price) * self.yscale)
            instg.add(Line(points=(x1, y1, x2, y2), width=1))
            self.canvas.add(instg)

            self.drawVolumeGraph(data, curIndex)

            if (curIndex % self.xgrid_num) == 0:
                self.drawXCoordinateInfo(curIndex)

            self.addBSPoint(curIndex)

            preIndex = curIndex
            prePrice = curPrice

        self.drawCrossLine(curIndex)

    def drawVolumeGraph(self, data, curIndex):
        instg = InstructionGroup(group="data")
        volume = data.get("vol")
        color = Color()
        color.rgba = self.VOLUME_COLOR
        instg.add(color)

        x1 = int(self.pos[0] + self.shift_left + curIndex * self.xscale)
        y1 = int(self.pos[1] + self.shift_bottom)
        x2 = int(self.pos[0] + self.shift_left + curIndex * self.xscale)
        y2 = int(self.pos[1] + self.shift_bottom + volume * self.vscale)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

    def addBSPoint(self, index):
        data = self.dataList[index]
        bstype = data.get("bs")
        if bstype != "":
            price = data.get("price")
            x1 = int(self.pos[0] + self.shift_left + index * self.xscale) - 5
            alabel = Label(text="",
                           size_hint=(None, None),
                           size=(5, 10),
                           markup=True)
            if bstype == "B":
                y1 = int(self.pos[1] + self.shift_bottom +
                         (price - self.min_price) * self.yscale) - 20
                alabel.pos = (x1, y1)
                alabel.color = self.TRADEB_SIG_COLOR
                alabel.text = "[b]" + "B" + "[/b]"
            elif bstype == "S":
                y1 = int(self.pos[1] + self.shift_bottom +
                         (price - self.min_price) * self.yscale) + 10
                alabel.pos = (x1, y1)
                alabel.color = self.TRADES_SIG_COLOR
                alabel.text = "[b]" + "S" + "[/b]"
            self.add_widget(alabel)

    def drawXCoordinateInfo(self, index):

        x0 = int(self.pos[0] + self.shift_left + index * self.xscale - 30)
        y0 = int(self.pos[1] + self.shift_bottom - 20)
        dateStr = self.dataList[index].get("date")
        alabel = SCordLabel(pos=(x0, y0), size_hint=(None, None))
        alabel.width = 60
        alabel.height = 20
        alabel.text = sutil.formatDate(dateStr)
        alabel.color = self.CORD_INFO_COLOR
        self.add_widget(alabel)

        timeStr = self.dataList[index].get("time")
        if timeStr != "0":
            x0 = int(self.pos[0] + self.shift_left + index * self.xscale - 30)
            y0 = int(self.pos[1] + self.shift_bottom - 40)
            alabel = SCordLabel(pos=(x0, y0), size_hint=(None, None))
            alabel.width = 60
            alabel.height = 20
            alabel.text = sutil.formatTime(timeStr)
            alabel.color = self.CORD_INFO_COLOR
            self.add_widget(alabel)

    def drawFrameGrid(self):

        # Start-01: 產生一繪製外框,線條及座標之物件
        rectParamDict = {}
        rectParamDict["canvas"] = self.canvas
        rectParamDict[
            "width"] = self.width - self.shift_left - self.shift_right
        rectParamDict[
            "height"] = self.height - self.shift_bottom - self.shift_top
        rectParamDict["x_start_pos"] = self.pos[0] + self.shift_left
        rectParamDict["y_start_pos"] = self.pos[1] + self.shift_bottom
        rectParamDict["rectColor"] = self.FRAME_COLOR
        rectParamDict["rectWidth"] = 1
        rectParamDict["gridColor"] = self.GRID_COLOR
        rectParamDict["gridWidth"] = 1
        rectParamDict["instGroup"] = "StrendGraph"
        smintimeChartUtil = SMinTimeCordUtil(rectParamDict)
        # End-01.

        smintimeChartUtil.drawRectGrid()  #繪製一矩形框

        gridColor = Color()
        gridColor.rgba = self.GRID_COLOR
        tmpNum = self.xgrid_num
        while (tmpNum < self.max_tickNum):
            instg = InstructionGroup(group="grid")
            x1 = int(self.pos[0] + self.shift_left + tmpNum * self.xscale)
            y1 = self.pos[1] + self.shift_bottom
            x2 = int(self.pos[0] + self.shift_left + tmpNum * self.xscale)
            y2 = self.pos[1] + self.height - self.shift_top
            instg.add(gridColor)
            instg.add(Line(points=(x1, y1, x2, y2), width=1))
            self.canvas.add(instg)
            tmpNum += self.xgrid_num

        pscale = (self.max_price - self.min_price) / 4.0
        for i in range(0, 5):
            y1 = int(self.pos[1] + self.shift_bottom +
                     (i * pscale * self.yscale))
            y2 = int(self.pos[1] + self.shift_bottom +
                     (i * pscale * self.yscale))
            if i != 0 and i != 4:
                instg = InstructionGroup(group="grid")
                x1 = self.pos[0] + self.shift_left
                x2 = self.pos[0] + self.width - self.shift_right
                instg.add(gridColor)
                instg.add(Line(points=(x1, y1, x2, y2), width=1))
                self.canvas.add(instg)

            cordPrice = i * pscale + self.min_price
            cordPriceStr = "{:7.2f}".format(cordPrice)
            x0 = self.pos[0] + 2
            #y0 = y1 - 8
            y0 = y1
            alabel = SCordLabel(text=cordPriceStr,
                                pos=(x0, y0),
                                size_hint=(None, None))
            alabel.width = self.shift_left - 2
            alabel.height = 16
            alabel.halign = "right"
            alabel.color = self.CORD_INFO_COLOR
            self.add_widget(alabel)

        smintimeChartUtil = None

    def getLineColor(self, price1, price2):
        color = Color()

        if price1 > price2:
            color.rgba = self.DOWN_COLOR
        elif price1 < price2:
            color.rgba = self.UP_COLOR
        else:
            color.rgba = self.EQUAL_COLOR
        return color

    def drawCrossLine(self, index):
        if self.dataList == None or index >= len(self.dataList):
            return

        data = self.dataList[index]

        price = data.get("price")

        color = Color()
        color.rgba = self.CROSS_LINE_COLOR

        self.canvas.remove_group("cross_line")

        instg = InstructionGroup(group="cross_line")
        instg.add(color)
        x1 = int(self.pos[0] + self.shift_left + index * self.xscale)
        y1 = self.pos[1] + self.shift_bottom
        x2 = int(self.pos[0] + self.shift_left + index * self.xscale)
        y2 = self.pos[1] + self.height - self.shift_top
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

        instg = InstructionGroup(group="cross_line")
        instg.add(color)
        x1 = self.pos[0] + self.shift_left
        y1 = int(self.pos[1] + self.shift_bottom +
                 (price - self.min_price) * self.yscale)
        x2 = self.pos[0] + self.width - self.shift_right
        y2 = int(self.pos[1] + self.shift_bottom +
                 (price - self.min_price) * self.yscale)
        instg.add(Line(points=(x1, y1, x2, y2), width=1))
        self.canvas.add(instg)

    def mousePos(self, *args):
        if len(args) >= 2:
            if self.dataList != None and len(self.dataList) != 0:
                index = int(
                    (args[1][0] - self.pos[0] - self.shift_left) / self.xscale)
                if index < len(self.dataList) and index >= 0:
                    data = self.dataList[index]
                    dateStr = str(data.get("date"))
                    timeStr = str(data.get("time"))
                    price = data.get("price")
                    self.drawCrossLine(index)

                    if self.infoLayout == None:
                        self.infoLayout = SInfoLayout(cols=1)
                        self.infoLayout.row_force_default = True
                        self.infoLayout.row_default_height = 20
                        self.infoLayout.col_force_default = True
                        self.infoLayout.col_default_width = 110
                        self.infoLayout.padding = [2, 1, 2, 1]
                        self.infoLayout.size_hint = (None, None)
                    else:
                        self.infoLayout.clear_widgets()
                    if self.infoLayout.parent == None:
                        self.add_widget(self.infoLayout)
                    x1 = int(self.pos[0] + self.shift_left +
                             index * self.xscale)
                    if (self.width - x1) < (self.infoLayout.width +
                                            self.shift_right):
                        pos_x = x1 - self.infoLayout.width
                    else:
                        pos_x = x1 + 5
                    y1 = int(self.pos[1] + self.shift_bottom +
                             (price - self.min_price) * self.yscale)
                    if (self.height - y1) < (self.infoLayout.height +
                                             self.shift_top):
                        pos_y = y1 - self.infoLayout.height
                    else:
                        pos_y = y1 + 5
                    self.infoLayout.pos = (pos_x, pos_y)

                    rowNum = 1
                    self.infoLayout.add_widget(self.info_date)
                    self.info_date.text = sutil.formatDate(dateStr)

                    if timeStr != "" and timeStr != "0":
                        rowNum += 1
                        self.infoLayout.add_widget(self.info_time)
                        self.info_time.text = sutil.formatTime(timeStr)

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_price)
                    self.info_price.text = "價:" + (
                        "{:7.2f}".format(price)).strip()

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_vol)
                    self.info_vol.text = "量:" + ("{:13.0f}".format(
                        data.get("vol"))).strip()

                    rowNum += 1
                    self.infoLayout.add_widget(self.info_amt)
                    self.info_amt.text = "金:" + ("{:13.0f}".format(
                        data.get("amt"))).strip()

                    bs = data.get("bs")
                    bsprice = data.get("bsprice")
                    if bs != "":
                        rowNum += 1
                        self.infoLayout.add_widget(self.info_bs)
                        self.info_bs.text = bs + ":" + (
                            "{:7.2f}".format(bsprice)).strip()

                    self.infoLayout.size = (110, rowNum * 20)
                else:
                    self.canvas.remove_group("cross_line")
                    if self.infoLayout != None:
                        if self.infoLayout.parent != None:
                            self.remove_widget(self.infoLayout)