``` import baostock as bs import pandas as pd import numpy as np import datetime from scipy.signal import argrelextrema from concurrent.futures import ThreadPoolExecutor, as_completed def basic_screening(df): """ 执行基本面筛选: 1. 剔除PE<=0或PE>30的股票 2. 筛选流通市值>100亿 3. 剔除PB<=0的股票 """ df = df.copy() # 转换数据类型 df['peTTM'] = pd.to_numeric(df['peTTM'], errors='coerce') df['total_mv'] = pd.to_numeric(df['total_mv'], errors='coerce') / 1e8 # 转换为亿 df['pbMRQ'] = pd.to_numeric(df['pbMRQ'], errors='coerce') # 设置筛选条件 conditions = ( (df['peTTM'].between(0, 30)) & # 市盈率筛选 (df['total_mv'] > 100) & # 流通市值筛选 (df['pbMRQ'] > 0) # 市净率筛选 ) return df[conditions].reset_index(drop=True) def get_stock_data(): """批量获取股票数据(减少API调用次数)""" # ...(原有代码保持不变)... def detect_divergence_wrapper(args): """包装函数用于多线程传参""" # ...(原有代码保持不变)... if __name__ == "__main__": def get_stock_data(): """批量获取股票数据(减少API调用次数)""" rs = bs.query_all_stock(day=datetime.datetime.now().strftime("%Y-%m-%d")) codes = [row[0] for row in rs.data if not row[0].startswith(('sh.688', 'sz.30'))] # 批量查询基本面数据(每次500支) BATCH_SIZE = 500 data_list = [] for i in range(0, len(codes), BATCH_SIZE): code_batch = codes[i:i + BATCH_SIZE] rs_batch = bs.query_stock_basic(code=",".join(code_batch)) data_list.extend(rs_batch.data) return pd.DataFrame(data_list, columns=['code', 'name', 'peTTM', 'total_mv', 'pbMRQ']) def detect_divergence_wrapper(args): """包装函数用于多线程传参""" code, end_date = args try: rs = bs.query_history_k_data_plus(code, "date,close", end_date=end_date, frequency="d", count=60) data = pd.DataFrame(rs.data, columns=['date', 'close']) # ...(保持原有计算逻辑不变)... return (code, divergence_flag) except Exception as e: print(f"Error processing {code}: {str(e)}") return (code, False) if __name__ == "__main__": bs.login() try: # 优化1:统一获取当前时间 end_date = datetime.datetime.now().strftime("%Y-%m-%d") # 优化2:并行执行主流程 with ThreadPoolExecutor(max_workers=16) as executor: # 阶段1:获取并筛选基础数据 df_base = get_stock_data() df_filtered = basic_screening(df_base) # 阶段2:多线程检测背离 futures = [] code_args = [(code, end_date) for code in df_filtered['code']] for args in code_args: futures.append(executor.submit(detect_divergence_wrapper, args)) # 收集结果 divergence_results = {} for future in as_completed(futures): code, result = future.result() divergence_results[code] = result df_filtered['rsi_divergence'] = df_filtered['code'].map(divergence_results) # 输出结果 final_result = df_filtered[df_filtered['rsi_divergence']] print("筛选结果:") print(final_result[['code', 'name', 'peTTM', 'total_mv']]) finally: bs.logout()```报错,IndentationError: expected an indented block after 'if' statement on line 42,请修正代码
时间: 2025-07-01 22:33:10 浏览: 24
<think>好的,我现在需要帮用户解决他遇到的Python代码缩进错误问题。用户提供的代码报错是IndentationError: expected an indented block after 'if' statement on line 42。首先,我要仔细看一下用户提供的代码,找到问题所在。
首先,用户贴出的代码中有一个明显的结构问题。在Python中,`if __name__ == "__main__":`语句后面必须跟一个缩进的代码块,而用户的代码在42行(根据报错提示)之后没有正确缩进。我注意到在用户的代码中,`if __name__ == "__main__":`下面紧接着的是函数`get_stock_data()`的定义,这显然是不正确的,因为函数定义不应该在if语句块内,除非它们被缩进。但根据代码结构,这里的`get_stock_data()`和后续的函数`detect_divergence_wrapper`以及主逻辑应该是属于if模块下的内容吗?
仔细看一下用户提供的代码结构,发现`if __name__ == "__main__":`后面直接跟着函数`get_stock_data()`的定义,而没有缩进。这会导致语法错误,因为Python期望在if语句后面有一个缩进的代码块。而实际上,用户可能在主条件块下定义了这些函数,或者在代码结构上存在混乱。
例如,在用户的代码中:
if __name__ == "__main__":
def get_stock_data():
# 函数体
这里,函数`get_stock_data()`被缩进在if语句块内,但根据用户的代码结构,这可能不是预期的。通常,函数定义不会放在if __name__ == "__main__":块里面,除非这些函数只在主程序运行时定义。不过,用户可能在粘贴代码时出现了格式错误,导致代码结构混乱。
另外,用户提供的代码中,在`if __name__ == "__main__":`下面,函数`get_stock_data()`和`detect_divergence_wrapper`可能被错误地缩进到了该条件语句下。正确的做法是,函数定义应该在该条件块之外,而主程序的执行代码才放在该块内。例如:
正确的结构应该是:
def get_stock_data():
# 函数体
def detect_divergence_wrapper(args):
# 函数体
if __name__ == "__main__":
# 主程序代码
而用户当前的代码结构是:
if __name__ == "__main__":
def get_stock_data():
# 函数体
def detect_divergence_wrapper(args):
# 函数体
这会导致在if语句块内定义了这些函数,但可能用户的意图并不是这样,特别是因为函数中可能调用了其他在主程序中的代码。另外,根据用户提供的错误信息,问题出在if语句后的缩进,所以可能是在if __name__ == "__main__":之后没有正确缩进主程序代码,而是直接开始定义函数,导致缩进错误。
查看用户代码的具体部分:
在代码的中间部分,用户有以下结构:
if __name__ == "__main__":
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
rs = bs.query_all_stock(day=datetime.datetime.now().strftime("%Y-%m-%d"))
codes = [row[0] for row in rs.data if not row[0].startswith(('sh.688', 'sz.30'))]
# 批量查询基本面数据(每次500支)
BATCH_SIZE = 500
data_list = []
for i in range(0, len(codes), BATCH_SIZE):
code_batch = codes[i:i + BATCH_SIZE]
rs_batch = bs.query_stock_basic(code=",".join(code_batch))
data_list.extend(rs_batch.data)
return pd.DataFrame(data_list, columns=['code', 'name', 'peTTM', 'total_mv', 'pbMRQ'])
这里明显存在缩进问题。`if __name__ == "__main__":`后面应该缩进接下来的代码块,而用户在这里直接定义了`get_stock_data()`函数,但该函数并没有缩进。这会导致Python解释器认为if语句后面没有任何代码块,从而引发IndentationError。
实际上,用户可能在粘贴代码时,把函数定义放在了if __name__ == "__main__":块之外,但由于格式错误,导致该函数被错误地包含在if语句中,或者缩进丢失。例如,正确的代码应该是:
def get_stock_data():
# 函数体
def detect_divergence_wrapper(args):
# 函数体
if __name__ == "__main__":
# 主程序代码
而用户的代码可能错误地将函数定义放在了if块内部,导致缩进问题。例如:
if __name__ == "__main__":
def get_stock_data():
...
这里,def前没有缩进,导致IndentationError。
因此,问题出现在`if __name__ == "__main__":`之后,函数定义没有正确缩进。正确的做法是将主程序中的执行代码放在该块内,而函数定义应该在该块之外。
因此,用户需要检查代码结构,确保所有在if __name__ == "__main__":下的代码正确缩进,并且函数定义在该块之外。例如,用户可能在主条件块下错误地重复定义了函数,或者在代码结构上出现了混乱。
现在需要具体查看用户提供的代码结构。根据用户提供的代码,在中间部分:
[原有代码...]
if __name__ == "__main__":
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
rs = bs.query_all_stock(day=datetime.datetime.now().strftime("%Y-%m-%d"))
codes = [row[0] for row in rs.data if not row[0].startswith(('sh.688', 'sz.30'))]
...
这里,def get_stock_data()应该是在if块之外定义的,而用户可能在if块之后直接开始定义函数,而没有缩进,导致错误。正确的结构应该是函数定义在if块之外,而主程序代码在if块内部,例如:
def get_stock_data():
# 函数体
def detect_divergence_wrapper(args):
# 函数体
if __name__ == "__main__":
bs.login()
try:
# 主程序代码
finally:
bs.logout()
但在用户的代码中,可能错误地将函数定义放在了if块内部,或者代码结构存在缩进问题。例如:
if __name__ == "__main__":
# 没有缩进的代码
def get_stock_data():
...
这会导致IndentationError,因为函数定义需要在if块内缩进。但更可能的是,用户可能在if块之后没有正确缩进主程序代码,或者函数定义的位置不正确。
根据用户提供的错误信息,错误出现在第42行的if语句后缺少缩进块。查看代码行数,可能需要数一下用户提供的代码的行号。根据用户提供的代码,可能在以下位置:
原代码中:
...
return df[conditions].reset_index(drop=True)
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
# ...(原有代码保持不变)...
def detect_divergence_wrapper(args):
"""包装函数用于多线程传参"""
# ...(原有代码保持不变)...
if __name__ == "__main__":
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
rs = bs.query_all_stock(day=datetime.datetime.now().strftime("%Y-%m-%d"))
codes = [row[0] for row in rs.data if not row[0].startswith(('sh.688', 'sz.30'))]
# 批量查询基本面数据(每次500支)
BATCH_SIZE = 500
data_list = []
for i in range(0, len(codes), BATCH_SIZE):
code_batch = codes[i:i + BATCH_SIZE]
rs_batch = bs.query_stock_basic(code=",".join(code_batch))
data_list.extend(rs_batch.data)
return pd.DataFrame(data_list, columns=['code', 'name', 'peTTM', 'total_mv', 'pbMRQ'])
这里,在`if __name__ == "__main__":`之后,用户没有缩进接下来的代码,而是直接定义了`get_stock_data()`函数,导致IndentationError。因为Python要求if语句后的代码块必须缩进,而这里的def语句没有缩进,因此报错。
因此,错误的原因是,在`if __name__ == "__main__":`之后,用户可能错误地重新定义了`get_stock_data()`函数,而没有正确缩进该函数,或者这个函数定义应该出现在if块之外,而主程序中的代码应缩进在if块内。
可能的解决方法是:
1. 检查用户是否在`if __name__ == "__main__":`块内重复定义了函数,如果是的话,应该将这些函数定义移到块外,并确保主程序逻辑正确缩进在块内。
例如,用户可能在主条件块下错误地重新定义了`get_stock_data()`,而原本这些函数已经定义在代码的前面部分。这会导致函数被覆盖,同时引发缩进错误。
在用户提供的代码中,前面已经有了`def get_stock_data()`的定义,然后在`if __name__ == "__main__":`块下再次定义同名函数,而没有缩进,导致语法错误。
所以,用户需要删除在if块内的重复函数定义,并将主程序代码正确缩进。例如,在用户提供的代码中,原代码结构可能如下:
在代码前半部分定义了:
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
# ...(原有代码保持不变)...
然后在`if __name__ == "__main__":`块下再次定义了同样的函数:
if __name__ == "__main__":
def get_stock_data():
"""批量获取股票数据(减少API调用次数)"""
rs = bs.query_all_stock(...)
...
这里,第二个`get_stock_data`的定义没有缩进,导致错误。因此,用户需要删除在if块下的重复函数定义,并将主程序代码(如bs.login()等)正确缩进在该块内。
因此,正确的代码结构应该是:
def basic_screening(df):
...
def get_stock_data():
... # 第一次定义
def detect_divergence_wrapper(args):
...
if __name__ == "__main__":
# 主程序代码,如bs.login()等,正确缩进
bs.login()
try:
...
finally:
bs.logout()
用户可能在if块内错误地再次定义了这些函数,而没有缩进,导致错误。例如,在用户提供的代码中,可能在if块下重复定义了`get_stock_data`和`detect_divergence_wrapper`,而这些函数已经在上方定义过了。
因此,解决方法是:
1. 确保在`if __name__ == "__main__":`块内没有函数定义,除非必要,并且正确缩进。
2. 检查主程序代码是否在if块内正确缩进。
具体到用户的代码,错误出现在:
if __name__ == "__main__":
def get_stock_data():
... # 这个函数定义没有缩进,导致IndentationError
因此,用户需要删除这个重复的函数定义,并将主程序代码放在if块内,正确缩进。或者,如果用户确实需要在主块内重新定义这些函数(虽然不太可能),则需要正确缩进这些def语句。
但更可能的情况是,用户在粘贴代码时,错误地将函数定义放在了if块之外,或者结构混乱。例如,在用户提供的代码中,原代码可能存在函数重复定义的问题,而主程序逻辑没有被正确缩进。
总结,用户需要做的是:
- 检查所有在`if __name__ == "__main__":`之后的代码是否被正确缩进。
- 确保在该块内没有重复定义函数,除非确实需要。
- 将主程序执行代码(如bs.login(), try块等)放在if块内,并正确缩进。
在用户提供的代码中,主程序部分应该是:
if __name__ == "__main__":
bs.login()
try:
# 优化1:统一获取当前时间
end_date = datetime.datetime.now().strftime("%Y-%m-%d")
# 优化2:并行执行主流程
with ThreadPoolExecutor(max_workers=16) as executor:
# 阶段1:获取并筛选基础数据
df_base = get_stock_data()
df_filtered = basic_screening(df_base)
# 阶段2:多线程检测背离
futures = []
code_args = [(code, end_date) for code in df_filtered['code']]
for args in code_args:
futures.append(executor.submit(detect_divergence_wrapper, args))
# 收集结果
divergence_results = {}
for future in as_completed(futures):
code, result = future.result()
divergence_results[code] = result
df_filtered['rsi_divergence'] = df_filtered['code'].map(divergence_results)
# 输出结果
final_result = df_filtered[df_filtered['rsi_divergence']]
print("筛选结果:")
print(final_result[['code', 'name', 'peTTM', 'total_mv']])
finally:
bs.logout()
但根据用户提供的代码,在`if __name__ == "__main__":`之后,函数`get_stock_data()`和`detect_divergence_wrapper`被重新定义,而没有缩进,导致错误。因此,用户需要删除这些重复的函数定义,并确保主程序代码正确缩进。
例如,用户可能在代码中重复定义了`get_stock_data`函数,一次在if块外,一次在if块内而没有缩进,导致错误。因此,修正方法是删除if块内的重复定义,并确保主程序代码正确缩进在if块内。
因此,最终的修正代码应该是将主程序执行部分(即从bs.login()开始的部分)正确缩进在if块内,并移除在if块内重复定义的函数。</think>该错误是由于`if __name__ == "__main__":`下方缺少代码块缩进导致的。修正后的完整代码如下:
```python
import baostock as bs
import pandas as pd
import numpy as np
import datetime
from scipy.signal import argrelextrema
from concurrent.futures import ThreadPoolExecutor, as_completed
def basic_screening(df):
"""执行基本面筛选"""
df = df.copy()
df['peTTM'] = pd.to_numeric(df['peTTM'], errors='coerce')
df['total_mv'] = pd.to_numeric(df['total_mv'], errors='coerce') / 1e8
df['pbMRQ'] = pd.to_numeric(df['pbMRQ'], errors='coerce')
conditions = (
(df['peTTM'].between(0, 30)) &
(df['total_mv'] > 100) &
(df['pbMRQ'] > 0)
)
return df[conditions].reset_index(drop=True)
def get_stock_data():
"""批量获取股票数据"""
rs = bs.query_all_stock(day=datetime.datetime.now().strftime("%Y-%m-%d"))
codes = [row[0] for row in rs.data if not row[0].startswith(('sh.688', 'sz.30'))]
BATCH_SIZE = 500
data_list = []
for i in range(0, len(codes), BATCH_SIZE):
code_batch = codes[i:i + BATCH_SIZE]
rs_batch = bs.query_stock_basic(code=",".join(code_batch))
data_list.extend(rs_batch.data)
return pd.DataFrame(data_list, columns=['code', 'name', 'peTTM', 'total_mv', 'pbMRQ'])
def detect_divergence_wrapper(args):
"""多线程包装函数"""
code, end_date = args
try:
rs = bs.query_history_k_data_plus(code, "date,close",
end_date=end_date,
frequency="d",
count=60)
data = pd.DataFrame(rs.data, columns=['date', 'close'])
# 此处应补充实际的背离检测逻辑
return (code, False) # 示例返回值
except Exception as e:
print(f"Error processing {code}: {str(e)}")
return (code, False)
if __name__ == "__main__": # <-- 错误发生在这里
bs.login()
try:
end_date = datetime.datetime.now().strftime("%Y-%m-%d")
with ThreadPoolExecutor(max_workers=16) as executor:
# 阶段1:获取并筛选基础数据
df_base = get_stock_data()
df_filtered = basic_screening(df_base)
# 阶段2:多线程检测背离
futures = []
code_args = [(code, end_date) for code in df_filtered['code']]
for args in code_args:
futures.append(executor.submit(detect_divergence_wrapper, args))
# 收集结果
divergence_results = {}
for future in as_completed(futures):
code, result = future.result()
divergence_results[code] = result
df_filtered['rsi_divergence'] = df_filtered['code'].map(divergence_results)
# 输出结果
final_result = df_filtered[df_filtered['rsi_divergence']]
print("筛选结果:")
print(final_result[['code', 'name', 'peTTM', 'total_mv']])
finally:
bs.logout()
```
主要修改点:
1. 将`if __name__ == "__main__":`下方的全部执行代码统一缩进4个空格
2. 移除了重复定义的`get_stock_data()`函数(原代码中存在两个相同函数定义)
3. 补充了`detect_divergence_wrapper`的默认返回值作为示例
建议后续改进:
1. 在`detect_divergence_wrapper`中补充实际的RSI背离检测逻辑
2. 增加异常处理重试机制(网络请求容易失败)
3. 添加进度条显示任务执行进度(tqdm库)
4. 设置请求间隔避免被封禁(time.sleep)
阅读全文
相关推荐



















