• PyQt5_寻找顶(底)背离并可视化


            技术指标的背离是指技术指标曲线的波动方向与价格曲线的趋势方向不一致,是使用技术指标最为重要的一点。在股市中,常见的技术指标的背离分为两种常见的形式,即顶背离和底背离。背离是预示市场走势即将见顶或者见底的依据,在价格还没有发生变化之前,技术指标会提前显示未来股价发展的趋势。

            顶部背离,是指在股市的上涨其中,股价的高点比前一点要高,而指标的高点却在下降,此时股票上涨的行情不会持久,投资者需谨慎,应考虑做空操作,以免被套牢。

            底部背离,是指股价下跌的过程中,技术指标虽然显示出比上一次的有所提高,但是股价仍然在下跌不止,此时股价的下跌行情快要见底。这是典型的买进信号,投资者可以做好准备,在适当的时间买入股票。

            在股市中,几乎所有的技术指标都有背离提示作用的功能,例如MACD、RSI和BOLL等。投资者可以用这些指标的背离功能来预测头部的风险和底部的买入机会,但在选择的时间参数上应当适当延长。由于日线存在着较多的骗线,一些技术指标会反复发出背离信号,使得其实用性不强,建议重点关注周线上的技术指标背离现象。

    PS:以上知识来自书籍《同花顺炒股从入门到精通》

    目录

    效果

    寻找背离策略代码

    可视化部分代码

    使用


    效果

    寻找背离策略代码

    思路:

    1. 找出K线的波峰波谷

    2. 找出指标的波峰波谷

    3. 将K线的波峰波谷和指标的波峰波谷对齐(就是将指标的高点和K线的高点对齐,指标的低点和K线的低点对齐,无法对齐的舍弃),本策略是K线高点和低点位置前后3个位置内指标出现了对应的高点和低点,就算是对齐,取最相近的那个点

    4. K线和指标的 高低点对齐后,每两个高点对比,如果K线升高,指标降低,或K线降低,指标升高,说明这对高点是顶背离;每两个低点对比,如果K线升高,指标降低,或K线降低,指标升高,说明是底背离。

    1. def res_peak_trough_list(df,peak_col,trough_col):
    2. '''
    3. 寻找波峰波谷
    4. :param df: 必须要有i_row
    5. :param peak_col: 波峰字段
    6. :param trough_col: 波谷字段
    7. :return:
    8. '''
    9. # 循环寻找波峰和波谷,交替寻找
    10. peak_list = []
    11. trough_list = []
    12. start_up_i_row = 0
    13. peak_yeah = False
    14. trough_yeah = False
    15. while True:
    16. if start_up_i_row >= len(df):
    17. break
    18. df00 = df.loc[df['i_row'] >= start_up_i_row].copy()
    19. df00['peak'] = df00[peak_col].cummax()
    20. df00['ext_00'] = df00['peak'] - df00['peak'].shift(-1)
    21. df00_p = df00.loc[(df00['ext_00'] == 0) & (df00['ext_00'].shift(-1) == 0) & (df00['ext_00'].shift(-2) == 0) & (
    22. df00['ext_00'].shift(-3) == 0) & (df00['ext_00'].shift(-4) == 0)].copy()
    23. df00['trough'] = df00[trough_col].cummin()
    24. df00['ext_10'] = df00['trough'] - df00['trough'].shift(-1)
    25. df00_t = df00.loc[(df00['ext_10'] == 0) & (df00['ext_10'].shift(-1) == 0) & (df00['ext_10'].shift(-2) == 0) & (
    26. df00['ext_10'].shift(-3) == 0) & (df00['ext_10'].shift(-4) == 0)].copy()
    27. if (df00_p is None or len(df00_p) <= 0) and (df00_t is not None and len(df00_t) > 0):
    28. trough_0 = df00_t.iloc[0]['i_row']
    29. if trough_yeah:
    30. trough_list.append(trough_0)
    31. break
    32. elif (df00_t is None or len(df00_t) <= 0) and (df00_p is not None and len(df00_p) > 0):
    33. peak_0 = df00_p.iloc[0]['i_row']
    34. if peak_yeah:
    35. peak_list.append(peak_0)
    36. break
    37. elif (df00_p is None or len(df00_p) <= 0) or (df00_t is None or len(df00_t) <= 0):
    38. break
    39. else:
    40. trough_0 = df00_t.iloc[0]['i_row']
    41. peak_0 = df00_p.iloc[0]['i_row']
    42. if peak_0 == trough_0:
    43. start_up_i_row += 1
    44. continue
    45. if peak_0 == 0:
    46. peak_yeah = False
    47. trough_yeah = True
    48. peak_list.append(peak_0)
    49. start_up_i_row = trough_0
    50. elif trough_0 == 0:
    51. trough_yeah = False
    52. peak_yeah = True
    53. trough_list.append(trough_0)
    54. start_up_i_row = peak_0
    55. else:
    56. if not trough_yeah and not peak_yeah:
    57. # 首次进入
    58. if peak_0 < trough_0:
    59. trough_yeah = True
    60. peak_list.append(peak_0)
    61. start_up_i_row = trough_0
    62. else:
    63. peak_yeah = True
    64. trough_list.append(trough_0)
    65. start_up_i_row = peak_0
    66. else:
    67. if peak_0 < trough_0:
    68. if peak_yeah:
    69. peak_list.append(peak_0)
    70. peak_yeah = False
    71. trough_yeah = True
    72. start_up_i_row = trough_0
    73. else:
    74. if trough_yeah:
    75. trough_list.append(trough_0)
    76. trough_yeah = False
    77. peak_yeah = True
    78. start_up_i_row = peak_0
    79. pass
    80. two_list = peak_list + trough_list
    81. two_list.sort()
    82. i = 0
    83. remove_list = []
    84. while i < len(two_list) - 2:
    85. one_i = two_list[i]
    86. two_i = two_list[i + 1]
    87. if one_i in peak_list and two_i in trough_list:
    88. if abs(one_i - two_i) <= 2:
    89. i += 2
    90. remove_list.append(one_i)
    91. remove_list.append(two_i)
    92. continue
    93. pass
    94. elif one_i in trough_list and two_i in peak_list:
    95. if abs(one_i - two_i) <= 2:
    96. i += 2
    97. remove_list.append(one_i)
    98. remove_list.append(two_i)
    99. continue
    100. pass
    101. else:
    102. pass
    103. i += 1
    104. pass
    105. two_list00 = []
    106. for item in two_list:
    107. if item in remove_list:
    108. continue
    109. two_list00.append(item)
    110. peak_list00 = []
    111. trough_list00 = []
    112. for item in two_list00:
    113. if item in peak_list:
    114. peak_list00.append(item)
    115. if item in trough_list:
    116. trough_list00.append(item)
    117. return peak_list00,trough_list00
    118. # 顶背离 和 底背离 索引对齐步骤
    119. def res_alignment_top_and_bottom_deviation_index(first_list,second_list):
    120. '''
    121. 顶背离 和 底背离
    122. 1. 对比时前后参差超过3,跳过
    123. :param first_list: 升序排列
    124. :param second_list: 升序排列
    125. :return:
    126. '''
    127. first_list00 = []
    128. second_list00 = []
    129. i = 0
    130. j = 0
    131. while i<len(first_list) and j<len(second_list):
    132. i_node = first_list[i]
    133. j0_node_list = []
    134. for j0 in range(j,len(second_list)):
    135. j0_node_list.append(abs(i_node-second_list[j0]))
    136. pass
    137. min_j0 = min(j0_node_list)
    138. if min_j0>3:
    139. i += 1
    140. continue
    141. min_index = j0_node_list.index(min_j0)
    142. ori_index = j + min_index
    143. first_list00.append(i_node)
    144. second_list00.append(second_list[ori_index])
    145. i += 1
    146. j = ori_index + 1
    147. return first_list00,second_list00
    148. def res_top_and_bottom_deviation(df,k_col_name_list,f_col_name_list):
    149. '''
    150. 顶背离 和 底背离
    151. :param df: 必要要有 i_row 列
    152. :param k_col_name_list: K线的[高点列,低点列]
    153. :param f_col_name_list: 指标的[高点列,低点列]
    154. :return:
    155. '''
    156. k_peak, k_trough = res_peak_trough_list(df, k_col_name_list[0], k_col_name_list[1])
    157. f_peak, f_trought = res_peak_trough_list(df, f_col_name_list[0], f_col_name_list[1])
    158. k_top, f_top = res_alignment_top_and_bottom_deviation_index(k_peak, f_peak)
    159. k_bottom, f_bottom = res_alignment_top_and_bottom_deviation_index(k_trough, f_trought)
    160. k_top_list = []
    161. f_top_list = []
    162. i = 0
    163. while i < len(k_top) - 2:
    164. one_k = k_top[i]
    165. two_k = k_top[i + 1]
    166. one_f = f_top[i]
    167. two_f = f_top[i + 1]
    168. one_k_val = df.iloc[one_k][k_col_name_list[0]]
    169. two_k_val = df.iloc[two_k][k_col_name_list[0]]
    170. one_f_val = df.iloc[one_f][f_col_name_list[0]]
    171. two_f_val = df.iloc[two_f][f_col_name_list[0]]
    172. if (one_k_val > two_k_val and one_f_val < two_f_val) or (one_k_val < two_k_val and one_f_val > two_f_val):
    173. k_top_list.append([(one_k, one_k_val), (two_k, two_k_val)])
    174. f_top_list.append([(one_f, one_f_val), (two_f, two_f_val)])
    175. i += 2
    176. pass
    177. else:
    178. i += 1
    179. pass
    180. k_bottom_list = []
    181. f_bottom_list = []
    182. i = 0
    183. while i < len(k_bottom) - 2:
    184. one_k = k_bottom[i]
    185. two_k = k_bottom[i + 1]
    186. one_f = f_bottom[i]
    187. two_f = f_bottom[i + 1]
    188. one_k_val = df.iloc[one_k][k_col_name_list[1]]
    189. two_k_val = df.iloc[two_k][k_col_name_list[1]]
    190. one_f_val = df.iloc[one_f][f_col_name_list[1]]
    191. two_f_val = df.iloc[two_f][f_col_name_list[1]]
    192. if (one_k_val > two_k_val and one_f_val < two_f_val) or (one_k_val < two_k_val and one_f_val > two_f_val):
    193. k_bottom_list.append([(one_k, one_k_val), (two_k, two_k_val)])
    194. f_bottom_list.append([(one_f, one_f_val), (two_f, two_f_val)])
    195. i += 2
    196. pass
    197. else:
    198. i += 1
    199. pass
    200. return k_top_list,f_top_list,k_bottom_list,f_bottom_list

    可视化部分代码

    需要导入的包、日期横坐标控件、K线图控件的代码请查看本人本栏目中其他博文,这里不再赘述。

    本文以KDJ指标为例,KDJ显示控件

    1. class KDJ_PlotWidget(pg.PlotWidget):
    2. def __init__(self):
    3. super().__init__()
    4. self.setLabel('left', 'KDJ')
    5. xax = RotateAxisItem(orientation='bottom')
    6. xax.setHeight(h=60)
    7. self.setAxisItems({'bottom':xax})
    8. self.color_k = (255,255,0) # 纯黄
    9. self.color_d = (30,144,255) # 道奇蓝
    10. self.color_j = (255,0,255) # 紫红色
    11. self.color_white = (248,248,255)
    12. pass
    13. def set_data(self,data:Dict[str,Any]):
    14. df = data['df']
    15. df.reset_index(inplace=True)
    16. tradeDate_list = df['tradeDate'].values.tolist()
    17. x = range(len(df))
    18. xTick_show = []
    19. x_dur = math.ceil(len(df)/20)
    20. for i in range(0,len(df),x_dur):
    21. xTick_show.append((i,tradeDate_list[i]))
    22. if len(df)%20!=0:
    23. xTick_show.append((len(df)-1,tradeDate_list[-1]))
    24. self.clear()
    25. self.addLegend()
    26. xax = self.getAxis('bottom')
    27. xax.setTicks([xTick_show])
    28. kdjk_fixed_target = pg.PlotCurveItem(x=np.array(x),y=np.array(df['kdj_k'].values.tolist()),name='K',pen=pg.mkPen({'color':self.color_k,'width':1}),connect='finite')
    29. kdjd_fixed_target = pg.PlotCurveItem(x=np.array(x),y=np.array(df['kdj_d'].values.tolist()),name='D',pen=pg.mkPen({'color':self.color_d,'width':1}),connect='finite')
    30. kdjj_fixed_target = pg.PlotCurveItem(x=np.array(x),y=np.array(df['kdj_j'].values.tolist()),name='J',pen=pg.mkPen({'color':self.color_j,'width':1}),connect='finite')
    31. self.addItem(kdjk_fixed_target)
    32. self.addItem(kdjd_fixed_target)
    33. self.addItem(kdjj_fixed_target)
    34. line_one_target = pg.InfiniteLine(pos=(0, 0), movable=False, angle=0,
    35. pen=pg.mkPen({'color': self.color_white, 'width': 1}),
    36. label='0',
    37. labelOpts=({'position':0.05})
    38. )
    39. line_two_target = pg.InfiniteLine(pos=(0, 20), movable=False, angle=0,
    40. pen=pg.mkPen({'color': self.color_white, 'width': 1}),
    41. label='20',
    42. labelOpts=({'position': 0.05})
    43. )
    44. line_three_target = pg.InfiniteLine(pos=(0, 50), movable=False, angle=0,
    45. pen=pg.mkPen({'color': self.color_white, 'width': 1}),
    46. label='50',
    47. labelOpts=({'position': 0.05})
    48. )
    49. line_four_target = pg.InfiniteLine(pos=(0, 80), movable=False, angle=0,
    50. pen=pg.mkPen({'color': self.color_white, 'width': 1}),
    51. label='80',
    52. labelOpts=({'position': 0.05})
    53. )
    54. self.addItem(line_one_target)
    55. self.addItem(line_two_target)
    56. self.addItem(line_three_target)
    57. self.addItem(line_four_target)
    58. self.enableAutoRange()
    59. pass

    结果显示控件

    1. class PyQtGraphScrollKWidget(QtWidgets.QWidget):
    2. def __init__(self):
    3. super().__init__()
    4. self.factor_widgets = {}
    5. self.init_data()
    6. self.init_ui()
    7. pass
    8. def init_data(self):
    9. # https://www.sioe.cn/yingyong/yanse-rgb-16/
    10. # self.color_line = (30, 144, 255)
    11. self.color_line = (255, 255, 0)
    12. self.color_highligh = (220,20,60)
    13. # 0 幽灵的白色; 1 纯黄; 2 紫红色; 3 纯绿; 4 道奇蓝
    14. self.color_list = [(248, 248, 255), (255, 255, 0), (255, 0, 255), (0, 128, 0), (30, 144, 255)]
    15. self.color_green = (34,139,34)
    16. self.color_red = (220,20,60)
    17. self.main_fixed_target_list = [] # 主体固定曲线,不能被删除
    18. self.whole_df = None
    19. self.whole_header = None
    20. self.whole_pd_header = None
    21. self.current_whole_data = None
    22. self.current_whole_df = None
    23. self.factor_list = None
    24. self.ma_list = None
    25. self.show_duration = []
    26. self.show_line = []
    27. self.show_segment = []
    28. self.detail_map = None
    29. self.factor_code_widgetname_map = {
    30. 'KDJ':'KDJ_PlotWidget'
    31. }
    32. pass
    33. def init_ui(self):
    34. self.whole_duration_label = QtWidgets.QLabel('左边界~右边界')
    35. pic_download_btn = QtWidgets.QPushButton('滚动截图')
    36. pic_download_btn.clicked.connect(self.pic_download_btn_clicked)
    37. layout_top = QtWidgets.QHBoxLayout()
    38. layout_top.addWidget(self.whole_duration_label)
    39. layout_top.addStretch(1)
    40. layout_top.addWidget(pic_download_btn)
    41. self.title_label = QtWidgets.QLabel('执行过程查看')
    42. self.title_label.setAlignment(Qt.AlignCenter)
    43. self.title_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')
    44. # 滚动区域开始
    45. self.pw_layout = QtWidgets.QVBoxLayout()
    46. self.scroll_area = QtWidgets.QScrollArea()
    47. self.scroll_area.setWidgetResizable(True)
    48. # self.scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
    49. layout_right = QtWidgets.QVBoxLayout()
    50. layout_right.addWidget(self.title_label)
    51. layout_right.addLayout(layout_top)
    52. layout_right.addWidget(self.scroll_area)
    53. self.setLayout(layout_right)
    54. pass
    55. def set_data(self, data: Dict[str, Any]):
    56. title_str = data['title_str']
    57. whole_header = data['whole_header']
    58. whole_df = data['whole_df']
    59. whole_pd_header = data['whole_pd_header']
    60. factor_list = data['factor_list']
    61. ma_list = data['ma_list']
    62. detail_map = data['detail_map']
    63. self.whole_header = whole_header
    64. self.whole_df = whole_df
    65. self.whole_pd_header = whole_pd_header
    66. self.factor_list = factor_list
    67. self.ma_list = ma_list
    68. if detail_map.get('duration') is not None:
    69. self.show_duration = detail_map['duration']
    70. if detail_map.get('line') is not None:
    71. self.show_line = detail_map['line']
    72. if detail_map.get('segment') is not None:
    73. self.show_segment = detail_map['segment']
    74. self.detail_map = detail_map
    75. self.title_label.setText(title_str)
    76. self.whole_duration_label.setText(f"{self.whole_df.iloc[0]['tradeDate']}~{self.whole_df.iloc[-1]['tradeDate']}")
    77. self.current_whole_df = self.whole_df.copy()
    78. self.caculate_and_show_data()
    79. pass
    80. def caculate_and_show_data(self):
    81. df = self.current_whole_df.copy()
    82. # df.reset_index(inplace=True)
    83. df['i_count'] = [i for i in range(len(df))]
    84. tradeDate_list = df['tradeDate'].values.tolist()
    85. x = range(len(df))
    86. xTick_show = []
    87. x_dur = math.ceil(len(df) / 20)
    88. for i in range(0, len(df), x_dur):
    89. xTick_show.append((i, tradeDate_list[i]))
    90. if len(df) % 20 != 0:
    91. xTick_show.append((len(df) - 1, tradeDate_list[-1]))
    92. candle_data = []
    93. for i, row in df.iterrows():
    94. candle_data.append(
    95. (row['i_count'], row['openPrice'], row['closePrice'], row['lowestPrice'], row['highestPrice']))
    96. self.current_whole_data = df.loc[:, self.whole_pd_header].values.tolist()
    97. # 开始配置显示的内容
    98. self.create_candle_widget()
    99. self.factor_widgets.clear()
    100. xax = self.pw.getAxis('bottom')
    101. xax.setTicks([xTick_show])
    102. # 标记技术图形 start
    103. if len(self.show_duration)>0:
    104. duration_list = self.show_duration[0]
    105. duration_color = self.show_duration[1]
    106. for i,item in enumerate(duration_list):
    107. for item00 in item:
    108. signal_fiexed_target = pg.LinearRegionItem([item00[0], item00[1]],
    109. movable=False, brush=(
    110. self.color_list[duration_color[i]][0], self.color_list[duration_color[i]][1], self.color_list[duration_color[i]][2], 50))
    111. self.pw.addItem(signal_fiexed_target)
    112. pass
    113. pass
    114. if len(self.show_line)>0:
    115. line_list = self.show_line[0]
    116. line_color = self.show_line[1]
    117. for i,item in enumerate(line_list):
    118. for item00 in item:
    119. signal_fiexed_target = pg.InfiniteLine(pos=(item00, 0), movable=False, angle=90,
    120. pen=pg.mkPen({'color': self.color_list[line_color[i]], 'width': 1})
    121. )
    122. self.pw.addItem(signal_fiexed_target)
    123. pass
    124. if len(self.show_segment)>0:
    125. for item in self.show_segment:
    126. r_target = pg.LineSegmentROI(item,pen={'color':self.color_red,'width':2},movable=False)
    127. self.pw.addItem(r_target)
    128. pass
    129. # 标记技术图形 end
    130. candle_fixed_target = CandlestickItem(candle_data)
    131. self.main_fixed_target_list.append(candle_fixed_target)
    132. self.pw.addItem(candle_fixed_target)
    133. if len(self.ma_list)>0:
    134. for i, item in enumerate(self.ma_list):
    135. item_color = i%len(self.color_list)
    136. line_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df[item].values.tolist()),
    137. pen=pg.mkPen({'color': self.color_list[item_color],
    138. 'width': 1}),
    139. connect='finite')
    140. self.main_fixed_target_list.append(line_fixed_target)
    141. self.pw.addItem(line_fixed_target)
    142. pass
    143. self.vLine = pg.InfiniteLine(angle=90, movable=False)
    144. self.hLine = pg.InfiniteLine(angle=0, movable=False)
    145. self.label = pg.TextItem()
    146. self.pw.addItem(self.vLine, ignoreBounds=True)
    147. self.pw.addItem(self.hLine, ignoreBounds=True)
    148. self.pw.addItem(self.label, ignoreBounds=True)
    149. self.vb = self.pw.getViewBox()
    150. self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
    151. # 其他项
    152. for item in self.factor_list:
    153. item_widget = eval(self.factor_code_widgetname_map[item])()
    154. item_widget.setMinimumHeight(300)
    155. item_widget.set_data({'df':self.current_whole_df.copy()})
    156. item_widget.setXLink(self.pw)
    157. # 标记 start
    158. if self.detail_map.get(item) is not None:
    159. target_detail = self.detail_map[item]
    160. if target_detail.get('duration') is not None:
    161. target_duration = target_detail['duration']
    162. target_list = target_duration[0]
    163. target_color = target_duration[1]
    164. for i,i0 in enumerate(target_list):
    165. for i00 in i0:
    166. signal_fiexed_target = pg.LinearRegionItem([i00[0], i00[1]],
    167. movable=False, brush=(
    168. self.color_list[target_color[i]][0], self.color_list[target_color[i]][1],
    169. self.color_list[target_color[i]][2], 50))
    170. item_widget.addItem(signal_fiexed_target)
    171. pass
    172. if target_detail.get('line') is not None:
    173. target_line = target_detail['line']
    174. target_list = target_line[0]
    175. target_color = target_line[1]
    176. for i, i0 in enumerate(target_list):
    177. for i00 in i0:
    178. signal_fiexed_target = pg.InfiniteLine(pos=(i00, 0), movable=False, angle=90,
    179. pen=pg.mkPen(
    180. {'color': self.color_list[target_color[i]],
    181. 'width': 1})
    182. )
    183. item_widget.addItem(signal_fiexed_target)
    184. pass
    185. if target_detail.get('segment') is not None:
    186. target_segment = target_detail['segment']
    187. for i00 in target_segment:
    188. r_target = pg.LineSegmentROI(i00, pen={'color': self.color_red, 'width': 2}, movable=False)
    189. item_widget.addItem(r_target)
    190. pass
    191. # 标记 end
    192. self.factor_widgets[item] = item_widget
    193. self.fill_pw_widget()
    194. self.pw.enableAutoRange()
    195. pass
    196. def mouseMoved(self, evt):
    197. pos = evt[0]
    198. if self.pw.sceneBoundingRect().contains(pos):
    199. mousePoint = self.vb.mapSceneToView(pos)
    200. index = int(mousePoint.x())
    201. if index >= 0 and index < len(self.current_whole_data):
    202. target_data = self.current_whole_data[index]
    203. html_str = ''
    204. for i, item in enumerate(self.whole_header):
    205. html_str += f"
      {item}:{target_data[i]}"
    206. self.label.setHtml(html_str)
    207. self.label.setPos(mousePoint.x(), mousePoint.y())
    208. self.vLine.setPos(mousePoint.x())
    209. self.hLine.setPos(mousePoint.y())
    210. pass
    211. def mouseClicked(self, evt):
    212. pass
    213. def updateViews(self):
    214. pass
    215. def fill_pw_widget(self):
    216. # 清空控件
    217. while self.pw_layout.count():
    218. item = self.pw_layout.takeAt(0)
    219. widget = item.widget()
    220. if widget is not None:
    221. widget.deleteLater()
    222. pass
    223. pass
    224. sc_child_widget = self.scroll_area.takeWidget()
    225. if sc_child_widget is not None:
    226. sc_child_widget.deleteLater()
    227. self.pw_layout.addWidget(self.pw)
    228. for item in self.factor_widgets.values():
    229. self.pw_layout.addWidget(item)
    230. one_sc_child_widget = QtWidgets.QWidget()
    231. one_sc_child_widget.setLayout(self.pw_layout)
    232. self.scroll_area.setWidget(one_sc_child_widget)
    233. pass
    234. def create_candle_widget(self):
    235. xax = RotateAxisItem(orientation='bottom')
    236. xax.setHeight(h=60)
    237. self.pw = pg.PlotWidget(axisItems={'bottom': xax})
    238. self.pw.setMinimumHeight(500)
    239. self.pw.setMouseEnabled(x=True, y=True)
    240. # self.pw.enableAutoRange(x=False,y=True)
    241. self.pw.setAutoVisible(x=False, y=True)
    242. pass
    243. def pic_download_btn_clicked(self):
    244. now_str = datetime.now().strftime('%Y%m%d%H%M%S')
    245. path,_ = QtWidgets.QFileDialog.getSaveFileName(
    246. self,
    247. '选择图片保存路径',
    248. f"pic_{now_str}",
    249. 'JPG(*.jpg)'
    250. )
    251. if not path:
    252. return
    253. widget = self.scroll_area.widget()
    254. pix = widget.grab()
    255. pix.save(path)
    256. pass
    257. pass

    使用

    1. if __name__ == '__main__':
    2. pre_path = r'D:/temp005/600660.csv'
    3. caculate_start_date_str = '2020-01-01'
    4. df = pd.read_csv(pre_path,encoding='utf-8')
    5. # 删除停牌的数据
    6. df = df.loc[df['openPrice'] > 0].copy()
    7. df['o_date'] = df['tradeDate']
    8. df['o_date'] = pd.to_datetime(df['o_date'])
    9. df = df.loc[df['o_date'] >= caculate_start_date_str].copy()
    10. # 保存未复权收盘价数据
    11. df['close'] = df['closePrice']
    12. # 计算前复权数据
    13. df['openPrice'] = df['openPrice'] * df['accumAdjFactor']
    14. df['closePrice'] = df['closePrice'] * df['accumAdjFactor']
    15. df['highestPrice'] = df['highestPrice'] * df['accumAdjFactor']
    16. df['lowestPrice'] = df['lowestPrice'] * df['accumAdjFactor']
    17. df.reset_index(inplace=True)
    18. df['i_row'] = [i for i in range(len(df))]
    19. factor_list = ['KDJ']
    20. df['kdj_k'], df['kdj_d'] = talib.STOCH(df['highestPrice'], df['lowestPrice'], df['closePrice'], fastk_period=5,
    21. slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
    22. df['kdj_j'] = 3 * df['kdj_k'] - 2 * df['kdj_d']
    23. k_top_list, f_top_list, k_bottom_list, f_bottom_list = res_top_and_bottom_deviation(df,['highestPrice','lowestPrice'],['kdj_k','kdj_k'])
    24. k_deviation_list = k_top_list + k_bottom_list
    25. f_deviation_list = f_top_list + f_bottom_list
    26. detail_map = {
    27. 'segment': k_deviation_list,
    28. 'KDJ': {
    29. 'segment': f_deviation_list
    30. }
    31. }
    32. columns_list = ['日期', '收盘价', '开盘价', '最高价', '最低价']
    33. columns_pd_list = ['tradeDate', 'closePrice', 'openPrice', 'highestPrice', 'lowestPrice']
    34. line_data = {
    35. 'title_str': '寻找顶背离和底背离',
    36. 'whole_header': columns_list,
    37. 'whole_df': df,
    38. 'whole_pd_header': columns_pd_list,
    39. 'detail_map': detail_map,
    40. 'factor_list': factor_list,
    41. 'ma_list': [],
    42. 'peak_trough_data': None
    43. }
    44. QtCore.QCoreApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    45. app = QtWidgets.QApplication(sys.argv)
    46. t_win = PyQtGraphScrollKWidget()
    47. t_win.set_data(line_data)
    48. t_win.showMaximized()
    49. app.exec()
    50. pass
  • 相关阅读:
    QGIS编译(跨平台编译)之五十一:qgis_native库在Qt Creator环境下编译的错误处理
    系统设计的端到端原则
    死锁产生的条件及其预防
    再见print(),有了 PySnooper 可轻松 debug 问题所在
    虹科直播 | CDS网络与数据安全专题技术直播重磅来袭,11.2起与您精彩相约
    无法直接打印变量值,是哪一步出错了吗?
    Django+vue前后端分离实战--vue后台管理系统--vue环境安装项目创建
    Linux运维相关基础知识
    InnoDB 数据页结构
    EN 14351-1门窗及配件—CE认证
  • 原文地址:https://blog.csdn.net/m0_37967652/article/details/128122115