VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 420
声望: 175

最近经常有朋友问MacdItem绘图部件显示范围有问题,因为老是有任务在手上,一直没有时间修改,现修改过了,测试没有问题,代码如下:

class MacdItem(ChartItem):
    """"""
    def __init__(self, manager: BarManager,short_window:int=12,long_window:int=26,M:int=9):
        """"""
        super().__init__(manager)

        self.white_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 255), width=1)
        self.yellow_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 0), width=1)
        self.red_pen: QtGui.QPen = pg.mkPen(color=(255, 0, 0), width=1)
        self.green_pen: QtGui.QPen = pg.mkPen(color=(0, 255, 0), width=1)

        self._values_ranges: Dict[Tuple[int, int], Tuple[float, float]] = {}
        self.last_range:Tuple[int, int] = (-1,-1)    # 最新显示K线索引范围

        self.short_window = short_window
        self.long_window = long_window
        self.M = M

        self.macd_data: Dict[int, List[float,float,float]] = {}


    def get_macd_value(self, ix: int) -> List:
        """"""
        if ix < 0:
            return (0.0,0.0,0.0)

        # When initialize, calculate all macd value
        if not self.macd_data:
            bars = self._manager.get_all_bars()
            close_data = [bar.close_price for bar in bars]

            diffs,deas,macds = talib.MACD(np.array(close_data), 
                                    fastperiod=self.short_window, 
                                    slowperiod=self.long_window, 
                                    signalperiod=self.M)

            for n in range(0,len(diffs)):
                self.macd_data[n] = [diffs[n],deas[n],macds[n]]

        # Return if already calcualted
        if ix in self.macd_data:
            return self.macd_data[ix]

        # Else calculate new value
        close_data = []
        for n in range(ix-self.long_window-self.M+1, ix + 1):
            bar = self._manager.get_bar(n)
            close_data.append(bar.close_price)

        diffs,deas,macds = talib.MACD(np.array(close_data), 
                                            fastperiod=self.short_window, 
                                            slowperiod=self.long_window, 
                                            signalperiod=self.M) 
        diff,dea,macd = diffs[-1],deas[-1],macds[-1]
        self.macd_data[ix] = [diff,dea,macd]

        return [diff,dea,macd]

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
        """"""
        macd_value = self.get_macd_value(ix)
        last_macd_value = self.get_macd_value(ix - 1)

        # # Create objects
        picture = QtGui.QPicture()
        painter = QtGui.QPainter(picture)

        # # Draw macd lines
        if np.isnan(macd_value[0]) or np.isnan(last_macd_value[0]):
            # print("略过macd lines0")
            pass
        else:
            end_point0 = QtCore.QPointF(ix, macd_value[0])
            start_point0 = QtCore.QPointF(ix - 1, last_macd_value[0])
            painter.setPen(self.white_pen)
            painter.drawLine(start_point0, end_point0)

        if np.isnan(macd_value[1]) or np.isnan(last_macd_value[1]):
            # print("略过macd lines1")
            pass
        else:
            end_point1 = QtCore.QPointF(ix, macd_value[1])
            start_point1 = QtCore.QPointF(ix - 1, last_macd_value[1])
            painter.setPen(self.yellow_pen)
            painter.drawLine(start_point1, end_point1)

        if not np.isnan(macd_value[2]):
            if (macd_value[2]>0):
                painter.setPen(self.red_pen)
                painter.setBrush(pg.mkBrush(255,0,0))
            else:
                painter.setPen(self.green_pen)
                painter.setBrush(pg.mkBrush(0,255,0))
            painter.drawRect(QtCore.QRectF(ix-0.3,0,0.6,macd_value[2]))
        else:
            # print("略过macd lines2")
            pass

        painter.end()
        return picture

    def boundingRect(self) -> QtCore.QRectF:
        """"""
        min_y, max_y = self.get_y_range()
        rect = QtCore.QRectF(
            0,
            min_y,
            len(self._bar_picutures),
            max_y
        )
        return rect

    def get_y_range(self, min_ix: int = None, max_ix: int = None) -> Tuple[float, float]:
        """ 
        获得3个指标在y轴方向的范围 
        hxxjava 修改,2022-11-15
        当显示范围改变时,min_ix,max_ix的值不为None,当显示范围不变时,min_ix,max_ix的值不为None,
        """  
        if not self.macd_data:
            # 如果MACD三个数据没有计算过
            return (-100,100)

        last_range = (min_ix,max_ix)
        if last_range == (None,None):   
            # 本次索引范围未改变           
            if self.last_range in self._values_ranges:  
                # 如果y方向范围已经保存,读取y方向范围
                result = self._values_ranges[self.last_range]
                return adjust_range(result)

            else:
                # 如果y方向范围没有保存,从macd_data重新计算y方向范围
                min_ix,max_ix = 0,len(self.macd_data)-1

                macd_list = list(self.macd_data.values())[min_ix:max_ix + 1]
                ndarray = np.array(macd_list)  

                max_price = np.nanmax(ndarray)
                min_price = np.nanmin(ndarray)

                # 保存y方向范围,同时返回结果
                result = (min_price, max_price)
                if result == (np.nan,np.nan):
                    # 前面的未计算出有效值会出现这种情况
                    return (-100,100)

                self.last_range = (min_ix,max_ix)
                self._values_ranges[self.last_range] = result
                return adjust_range(result)

        """ 以下为显示范围变化时 """
        if last_range in self._values_ranges:
            # 该范围已经保存过y方向范围
            # 取得y方向范围,返回结果
            self.last_range = last_range
            result = self._values_ranges[last_range]
            return adjust_range(result)

        # 该范围没有保存过y方向范围,从macd_data重新计算y方向范围
        min_ix = max(0,min_ix)
        max_ix = min(max_ix,len(self.macd_data)-1)

        macd_list = list(self.macd_data.values())[min_ix:max_ix+1]
        ndarray = np.array(macd_list) 

        max_price = np.nanmax(ndarray)
        min_price = np.nanmin(ndarray)

        # 取得y方向范围,返回结果
        result = (min_price, max_price)

        if result == (np.nan,np.nan):
            # 前面的未计算出有效值会出现这种情况
            return (-100,100)

        # print(f"result1={result}")
        self.last_range = (min_ix,max_ix)
        self._values_ranges[self.last_range] = result

        self.min_ix,self.max_ix = last_range
        return adjust_range(result)


    def get_info_text(self, ix: int) -> str:
        """ """
        barscount = len(self._manager._bars) # hxxjava debug
        if ix in self.macd_data:
            [diff,dea,macd] = self.macd_data[ix]
            words = [
                f"diff {diff:.3f}"," ",
                f"dea {dea:.3f}"," ",
                f"macd {macd:.3f}",
                f"barscount={ix,barscount}"
                ]
            text = "\n".join(words)
        else:
            text = "diff - \ndea - \nmacd -"

        return text
Member
avatar
加入于:
帖子: 11
声望: 0

谢谢hxxjava老师分享!好人发大财!

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】