python:RSI 指标,超买 overbuy, 超卖 oversold

该Python脚本利用tushare获取股票数据,通过talib库计算6日和14日RSI指标,判断超买和超卖情况,并绘制收盘价和RSI曲线图。脚本还包含了对RSI超过80和低于20时的标记功能。

RSI 为1978年美国作者Welles Wilder JR.在著作(New Concepts in Technical Trading Systems)中所提出的交易方法之一,所谓RSI英文全名为(Relative Strenth Index)中文名称为相当强弱指标。RSI的基本原理是在一个正常的股市中,多空买卖双方的力道必须取得均衡,股价才能稳定;而RSI是对于固定期间内,股价上涨总幅度平均指占总幅度平均值的比例。

    买卖原则:
    1. RSI值于0-100之间呈常态分配,
    2. 当6日RSI值在80%以上时,股市呈超买现象,若出现M头,为卖出时机。
    3. 当6日RSI值在20%以下时,股市呈超卖现象,若出现W底为买进时机。
    4. RSI一般选用6天;12天,24天作为参考基期,基期越长越有趋势性-慢速RSI,基期越短越有敏感性-快速RSI,
    5. 当快速RSI由下往上突破慢速RSI时,为买进时机;当快速RSI由上往下跌破慢速RSI时,为卖出时机

talib_rsi.py 

# -*- coding: utf-8 -*-
import os, sys
import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import talib

if len(sys.argv) ==2:
    code = sys.argv[1]
else:
    print('usage: python talib_rsi.py stockcode ')
    sys.exit(1)

if len(code) !=6:
    print('stock code length: 6')
    sys.exit(2)

df = ts.get_k_data(code)
if df.empty ==True:
    print(
代码报错:C:\Users\28729\AppData\Local\Temp\ipykernel_2060\857681138.py:10: FutureWarning: Automatic reindexing on DataFrame vs Series comparisons is deprecated and will raise ValueError in a future version. Do `left, right = left.align(right, axis=1, copy=False)` before e.g. `left == right` df['MA_Signal'] = np.where(df['Close'] > df[f'MA_{ma_window}'], 1, -1)原始代码:def generate_signals(df, ma_window=50, rsi_oversold=30, rsi_overbought=70): """ 生成MA-RSI交易信号 ma_window: 使用的MA周期 rsi_oversold/overbought: RSI阈值 """ df = df.copy() # 趋势信号 df['MA_Signal'] = np.where(df['Close'] > df[f'MA_{ma_window}'], 1, -1) # RSI动量信号 df['RSI_Signal'] = 0 # RSI区反弹 (连续两日低于阈值后回升) df.loc[(df['RSI'].shift(1) < rsi_oversold) & (df['RSI'] > rsi_oversold), 'RSI_Signal'] = 1 # RSI超买区回落 df.loc[(df['RSI'].shift(1) > rsi_overbought) & (df['RSI'] < rsi_overbought), 'RSI_Signal'] = -1 # 综合信号生成 df['Signal'] = 0 # 买入条件:趋势向上且RSI反弹 df.loc[(df['MA_Signal'] == 1) & (df['RSI_Signal'] == 1), 'Signal'] = 1 # 出条件:趋势向下或RSI回落 df.loc[(df['MA_Signal'] == -1) | (df['RSI_Signal'] == -1), 'Signal'] = -1 return df strategy_data = generate_signals(aapl_data) strategy_data.head() def generate_signals(df, ma_window=50, rsi_oversold=30, rsi_overbought=70): """ 生成MA-RSI交易信号 ma_window: 使用的MA周期 rsi_oversold/overbought: RSI阈值 """ df = df.copy() # 趋势信号 df['MA_Signal'] = np.where(df['Close'] > df[f'MA_{ma_window}'], 1, -1) # RSI动量信号 df['RSI_Signal'] = 0 # RSI区反弹 (连续两日低于阈值后回升) df.loc[(df['RSI'].shift(1) < rsi_oversold) & (df['RSI'] > rsi_oversold), 'RSI_Signal'] = 1 # RSI超买区回落 df.loc[(df['RSI'].shift(1) > rsi_overbought) & (df['RSI'] < rsi_overbought), 'RSI_Signal'] = -1 # 综合信号生成 df['Signal'] = 0 # 买入条件:趋势向上且RSI反弹 df.loc[(df['MA_Signal'] == 1) & (df['RSI_Signal'] == 1), 'Signal'] = 1 # 出条件:趋势向下或RSI回落 df.loc[(df['MA_Signal'] == -1) | (df['RSI_Signal'] == -1), 'Signal'] = -1 return df strategy_data = generate_signals(aapl_data) strategy_data.head() ,已知数据中前五十行有缺失值
03-29
<think>好的,我现在需要解决用户提出的问题。用户在使用他们提供的Python代码时遇到了一个FutureWarning,提示在DataFrame和Series比较时自动重新索引已经被弃用,建议使用left.align(right, axis=1, copy=False)进行处理。原始代码中的错误出现在生成MA_Signal这一行,使用了np.where比较df['Close']和df[f'MA_{ma_window}']。此外,用户还提到数据的前50行有缺失值。 首先,我需要理解这个警告的原因。FutureWarning通常意味着当前代码在未来的版本中可能会引发错误。这里的问题在于DataFrame和Series之间的比较操作。当使用df['Close'](一个Series)与df[f'MA_{ma_window}'](另一个Series)进行比较时,如果它们的索引不一致,Pandas会自动对齐索引,这被称为自动重新索引。但未来的版本将不再支持这种操作,需要显式地对齐。 接下来,我需要检查用户的代码。生成MA_Signal的行是使用np.where比较两个Series。假设df['Close']和df[f'MA_{ma_window}']的长度相同,但由于ma_window=50,移动平均列的前50行可能为NaN,这可能导致索引不一致?或者可能存在其他原因导致索引不匹配,比如数据被过滤或处理过,导致两个Series的索引不完全一致? 用户提到数据中前50行有缺失值,这可能是因为移动平均的计算导致前ma_window-1行是NaN。例如,计算50日移动平均,前49行的值会是NaN,而第50行开始才有有效值。这时候,当比较Close和MA_50时,前49行的MA_50是NaN,而Close可能有值。这时候,比较操作可能会导致索引不一致吗?或者是否因为某些操作导致两个Series的索引被改变? 可能的解决方法是显式地对齐两个Series的索引。根据警告信息的建议,应该使用left, right = left.align(right, axis=1, copy=False),但在这里比较的是两个Series,所以应该考虑轴的问题。不过,这里比较的是两个列,即两个Series,它们的索引应该相同,因为来自同一个DataFrame。但可能在某些情况下,比如数据被切片或处理过,导致它们的索引不一致。比如,在生成MA_50列时,可能存在某些操作导致其索引与Close列不同? 或者,是否因为用户的数据中存在索引不连续的情况,例如在计算移动平均后,导致MA_50列的索引与Close的索引部分不一致?或者,当使用df = df.copy()时,是否导致某些索引的变化? 另外,用户提到数据的前五十行有缺失值,这可能是因为移动平均的计算导致MA_50列的前49个值为NaN(如果窗口是50的话,通常是从第50个值开始有数据)。这时候,在比较时,如果两个Series的索引是相同的,那么即使有NaN,比较仍然可以进行,但结果会是False或者NaN。不过,这里的警告可能不是因为NaN的存在,而是因为两个Series的索引本身不一致,导致Pandas需要自动重新索引,而这种行为在将来会被禁止。 所以解决方法应该是显式地对齐这两个Series,确保它们的索引一致,然后再进行比较。根据警告的建议,可以使用align方法。对于两个Series来说,应该使用axis=0,因为Series是1维的,而align的axis参数对于Series来说可能不需要,或者应该设置为0。或者,在比较之前,将两个Series对齐,确保它们的索引一致。 具体到代码中,用户原来的代码是: df['MA_Signal'] = np.where(df['Close'] > df[f'MA_{ma_window}'], 1, -1) 这里,df['Close']和df[f'MA_{ma_window}']都是DataFrame的列,即Series。假设它们的索引是相同的,那么比较不会有问题。但可能存在某些情况下,它们的索引不一致,例如在数据预处理中被重置了索引,或者某些操作导致部分行被删除,导致两个列的索引不一致。这时候,比较操作会触发自动对齐,而未来版本将不允许这种情况,因此需要显式对齐。 因此,正确的做法是在比较之前,将两个Series对齐。例如: close_series, ma_series = df['Close'].align(df[f'MA_{ma_window}'], axis=0, copy=False) df['MA_Signal'] = np.where(close_series > ma_series, 1, -1) 或者,更简单的方式是确保两个列来自同一个DataFrame,它们的索引本来就是一致的,所以可能不需要align。但用户的数据可能存在索引问题。比如,在生成MA_50列时,可能使用了某种方式导致其索引与原始数据不同? 另外,用户的数据中前50行有缺失值,这可能是因为移动平均的计算导致的,例如计算MA_50的时候,前49行(如果窗口是50的话)是NaN,而第50行开始有值。这时候,当比较Close和MA_50时,前49行的MA_50是NaN,而Close可能有数值。在这种情况下,比较的结果会是False,或者在np.where中如何处理NaN? 可能的问题并不是因为NaN的存在,而是因为索引不一致。因此,显式对齐可以解决这个问题。 另外,用户可能在计算MA时使用的是rolling方法,例如: df[f'MA_{ma_window}'] = df['Close'].rolling(window=ma_window).mean() 这会导致前ma_window-1行的值为NaN。此时,df[f'MA_{ma_window}']的索引与df['Close']的索引是一致的,所以两者的索引应该相同。因此,这种情况下索引应该是一致的,可能不存在索引不对齐的问题。那为什么会出现警告呢? 可能用户使用的Pandas版本较新,该版本中即使索引一致,当比较DataFrame和Series时(比如,如果其中一个操作数是DataFrame,另一个是Series),会触发自动对齐的问题?或者,问题中的比较操作实际上是在DataFrame和Series之间进行比较?比如,用户可能不小心将某个列作为DataFrame而不是Series? 需要检查代码中的df['Close']是否是Series。假设是的,那么比较两个Series应该没有问题。但在某些情况下,比如,如果df[f'MA_{ma_window}']是一个DataFrame而不是Series?这不太可能,因为用户使用f字符串来生成列名,应该是正确的列名,作为Series。 或者,是否用户代码中的ma_window变量是字符串类型,导致列名不正确?例如,ma_window被设置为字符串'50'而不是整数50,导致列名不正确,从而引发错误?但错误提示中显示列名是'MA_50',所以这可能不是问题。 现在回到警告本身。该警告提示的是在DataFrame和Series比较时自动重新索引被弃用。但用户的代码中比较的是两个Series(df['Close']和df['MA_50']),所以可能问题出在这里。或者,是否在比较时,其中一个操作数是DataFrame,另一个是Series? 比如,假设用户错误地将某个操作数变成了DataFrame,例如df[['Close']]是一个DataFrame,而df['MA_50']是一个Series。此时,比较这两个对象时,Pandas会进行自动对齐,导致警告。 但在用户的代码中,确实是使用df['Close'],即Series,而df[f'MA_{ma_window}']也是Series,所以比较应该是两个Series,这时候为什么会触发DataFrame vs Series的比较呢? 这时候,我可能理解错了警告的内容。或者,可能用户的代码中存在其他情况,比如,df['Close']可能是一个DataFrame?这不太可能,除非列名中有重复,导致返回的是DataFrame而不是Series。例如,如果数据中有多列名为'Close',则df['Close']会返回一个DataFrame。但通常这是不可能的,所以用户可能的数据结构是正确的。 这时候,可能需要重新检查代码中的比较操作。例如,当使用np.where时,第一个参数是条件,这里比较两个Series,但可能在某些情况下,这两个Series的索引不同,导致Pandas需要对齐,从而触发警告。 因此,正确的解决方法是使用align方法对齐两个Series的索引,再进行条件判断。 所以,修改后的代码应该是: close_series = df['Close'] ma_series = df[f'MA_{ma_window}'] # 对齐索引 close_aligned, ma_aligned = close_series.align(ma_series, axis=0, copy=False) # 然后比较 df['MA_Signal'] = np.where(close_aligned > ma_aligned, 1, -1) 但align方法对于两个Series来说,axis参数可能不是必须的,或者可以省略。或者,axis=0是正确的,因为Series是沿着行索引对齐的。 此外,用户提到数据的前50行有缺失值,这可能是因为移动平均的计算导致MA_50列的前49个值为NaN。此时,在比较时,这些位置会导致结果为False,从而在np.where中被赋值为-1。这可能不是错误,但用户需要注意NaN的处理。例如,如果希望当MA_50为NaN时,不生成信号,可能需要额外的处理。但根据用户原来的代码逻辑,可能已经接受这种情况,因为MA_Signal会在前49行被赋值为-1,当Close存在时。 综上,解决这个警告的方法是在比较之前显式对齐两个Series。因此,修改生成MA_Signal的代码行,使用align方法对齐两个Series的索引,再进行比较。 另外,用户的数据中存在前50行的缺失值,这可能是因为移动平均的计算,所以在调用generate_signals函数之前,需要确保已经正确计算了MA列。例如,用户是否在调用generate_signals之前正确计算了移动平均列?例如,是否在aapl_data中已经存在'MA_50'列?或者是否应该在generate_signals函数内部计算MA列? 例如,用户提供的原始代码中的generate_signals函数并没有计算MA列,而是直接使用df[f'MA_{ma_window}']。因此,可能在调用该函数之前,用户需要先计算移动平均列。例如: aapl_data[f'MA_{ma_window}'] = aapl_data['Close'].rolling(window=ma_window).mean() 如果用户没有做这一步,那么df[f'MA_{ma_window}']列不存在,会导致KeyError。但用户的问题中没有提到KeyError,而是提到了FutureWarning,所以假设该列已经正确生成。 但可能的问题是,在计算移动平均时,由于窗口为50,前49行是NaN,这可能导致在比较时,当ma_window=50时,前49行的MA_50是NaN,而Close的值是存在的。此时,比较Close > NaN的结果是False,因此np.where会返回-1。这可能符合用户的预期,但需要注意NaN的处理。 现在回到警告的解决,用户需要修改生成MA_Signal的那一行代码,使用align方法对齐两个Series。例如: # 趋势信号 close_series = df['Close'] ma_series = df[f'MA_{ma_window}'] close_aligned, ma_aligned = close_series.align(ma_series, axis=0) df['MA_Signal'] = np.where(close_aligned > ma_aligned, 1, -1) 这样,两个Series的索引将被显式对齐,避免自动重新索引导致的警告。 此外,用户提到数据中前五十行有缺失值,可能需要在计算信号时处理这些NaN。例如,在移动平均列中前49行是NaN,所以在这些行中,MA_Signal会被赋值为-1。如果用户希望在这些位置不生成信号,可能需要将MA_Signal设为0或其他默认值。但根据用户原来的代码逻辑,他们可能已经接受这一点。 综上,解决警告的方法是显式对齐两个Series的索引,然后进行比较。此外,用户需要确保在生成MA列时正确处理NaN,或者在信号生成时处理这些NaN的情况。 最后,用户可能还需要检查他们的Pandas版本,并考虑升级或降级以适应API的变化,但更合理的解决方法是修改代码以适应未来的版本。</think>为消除FutureWarning并确保代码兼容性,需要显式对齐DataFrame列。警告产生的原因是Pandas未来版本不再允许自动对齐不同索引的Series/DataFrame比较: ```python def generate_signals(df, ma_window=50, rsi_oversold=30, rsi_overbought=70): df = df.copy() # 显式对齐索引 close, ma = df['Close'].align(df[f'MA_{ma_window}'], axis=0) df['MA_Signal'] = np.where(close > ma, 1, -1) # RSI信号部分保持不变 df['RSI_Signal'] = 0 df.loc[(df['RSI'].shift(1) < rsi_oversold) & (df['RSI'] > rsi_oversold), 'RSI_Signal'] = 1 df.loc[(df['RSI'].shift(1) > rsi_overbought) & (df['RSI'] < rsi_overbought), 'RSI_Signal'] = -1 # 处理前NAN行(移动平均导致的缺失值) df['MA_Signal'] = df['MA_Signal'].fillna(0) # 可选操作 # 综合信号生成 df['Signal'] = 0 df.loc[(df['MA_Signal'] == 1) & (df['RSI_Signal'] == 1), 'Signal'] = 1 df.loc[(df['MA_Signal'] == -1) | (df['RSI_Signal'] == -1), 'Signal'] = -1 return df ``` **修改说明:** 1. 使用`.align()`方法显式对齐'Close'和移动平均列的索引 2. 添加`fillna(0)`可选操作处理移动平均产生的NaN值(前50行) 3. 保持其他信号生成逻辑不变
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值