You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加速Python股票筛选器代码?优化慢运行选股脚本

优化Python股票筛选代码的运行效率

我有一段可正常运行但速度极慢的Python股票筛选代码,每只股票的信息处理耗时约10秒,若处理2000只股票则需数小时。作为编程新手,我希望能对代码进行修改以提升运行效率,以下是我的代码:

import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.widgets import Cursor
import numpy as np
from IPython.display import display
from datetime import datetime
from currency_converter import CurrencyConverter
c = CurrencyConverter()

tickers = ['EDF.PA', 'anto.l', 'meta', 'iag.l', 'PFE','PKG','0700.hk', 'mbg.de']


df = pd.DataFrame({'Company': [''], 'P/S': [''],'P/E': [''],'P/B': [''],'Profit Margin(%)': [''],'ROE(%)': [''],'Current Ratio': [''],})
row = 0
for ticker in tickers: 
    ticker = yf.Ticker(ticker)
 
    quarterly_financials = ticker.quarterly_financials
    quarterly_financials['TTM'] = quarterly_financials.sum(axis=1)

    quarterly_balance_sheet = ticker.quarterly_balance_sheet
    quarterly_balance_sheet = quarterly_balance_sheet.iloc[:, [3, 2, 1, 0]]
    quarterly_balance_sheet.fillna('none', inplace=True)
    
    TTM = quarterly_balance_sheet.mean(axis=1)
    TTM.fillna('none', inplace=True)

    try:
        balance_sheet = ticker.balance_sheet
        balance_sheet = balance_sheet.iloc[:, [3, 2, 1, 0]]
    except Exception:
        pass


    #...Data...
    try:
        # Changes value of 'currency from 'GBp' to 'GBP'
        if ticker.info['currency'] == 'GBp':
            ticker.info['currency'] = 'GBP'
        # Makes sure market cap currency matches business currency
        if ticker.info['currency'] == ticker.info['financialCurrency']:
            MarketCap = ticker.info['marketCap']
        elif ticker.info['currency'] != ticker.info['financialCurrency']:
            MarketCap = ticker.info['marketCap']
            x = ticker.info['currency']
            y = ticker.info['financialCurrency']
            # Converts the market cap from, x (market cap currency), to y (financial currency), using the last available rate
            MarketCap = c.convert(MarketCap, x, y)
    except:
        MarketCap = 0
    
    try:
        TotalRevenue = (quarterly_financials.loc['Total Revenue'].iloc[-1])
    except:
        TotalRevenue = 0

    try:
        NetIncome = (quarterly_financials.loc['Net Income'].iloc[-1])
    except:
        NetIncome = 0

    try:
        TotalCurrentAssets = (quarterly_balance_sheet.loc['Total Current Assets'].iloc[-1])
        TotalCurrentLiabilities = (quarterly_balance_sheet.loc['Total Current Liabilities'].iloc[-1])
        TotalCurrentAssets/TotalCurrentLiabilities
    except:
        try:
            TotalCurrentAssets = (TTM.loc['Total Current Assets'])
            TotalCurrentLiabilities = (TTM.loc['Total Current Liabilities'])
            TotalCurrentAssets/TotalCurrentLiabilities   
        except:
            try:
                TotalCurrentAssets = (balance_sheet.loc['Total Current Assets'].iloc[-1])
                TotalCurrentLiabilities = (balance_sheet.loc['Total Current Liabilities'].iloc[-1])
                TotalCurrentAssets/TotalCurrentLiabilities
            except:
                TotalCurrentAssets = 0
                TotalCurrentLiabilities = 0
                print("Current Assets and Liabilities 4")

    try: 
        TotalAssets = (quarterly_balance_sheet.loc['Total Assets'].iloc[-1])
        TotalLiabilities = (quarterly_balance_sheet.loc['Total Liab'].iloc[-1])
        TotalAssets - TotalLiabilities
    except:
        try:
            TotalAssets = (TTM.loc['Total Assets'].iloc[-1])
            TotalLiabilities = (TTM.loc['Total Liab'].iloc[-1])
            TotalAssets - TotalLiabilities
        except:
            try:
                TotalAssets = (balance_sheet.loc['Total Assets'].iloc[-1])
                TotalLiabilities = (balance_sheet.loc['Total Liab'].iloc[-1])
                TotalAssets - TotalLiabilities
            except:
                TotalAssets = 0
                TotalLiabilities = 0 



    #...Creates Stock Screen df...
    try:
        df.at[row, 'Company'] = ticker.info['longName']
    except:
        df.at[row, 'Company'] = ''

    try:
        df.at[row, 'P/S'] = round((MarketCap/TotalRevenue), 2)
    except:
        df.at[row, 'P/S'] = 0

    try:
        df.at[row, 'P/E'] = round((MarketCap / NetIncome), 2)
    except:
        df.at[row, 'P/E'] = 0

    try:
        df.at[row, 'P/B'] = round((MarketCap / (TotalAssets - TotalLiabilities)), 2)
    except:
        df.at[row, 'P/B'] = 0

    try:
        df.at[row, 'Profit Margin(%)'] = round((NetIncome / TotalRevenue)*100, 2)
    except:
        df.at[row, 'Profit Margin(%)'] = 0

    try:
        df.at[row, 'ROE(%)'] = round((NetIncome / (TotalAssets - TotalLiabilities))*100, 2)
    except:
        df.at[row, 'ROE(%)'] = 0

    try:
        df.at[row, 'Current Ratio'] = TotalCurrentAssets/TotalCurrentLiabilities
    except:
        df.at[row, 'Current Ratio'] = 0
    
    row = row+1

display(df)

优化建议

1. 并行处理网络请求(最核心提速点)

代码慢的主要原因是串行等待网络响应:每只股票都要单独请求yfinance接口,大部分时间耗在等待上。改用线程池并行处理,一次性批量请求多只股票数据:

from concurrent.futures import ThreadPoolExecutor
import yfinance as yf
import pandas as pd
from currency_converter import CurrencyConverter

c = CurrencyConverter()

def process_single_ticker(ticker_symbol):
    """单独处理一只股票,返回结果字典"""
    ticker = yf.Ticker(ticker_symbol)
    result = {
        'Company': '',
        'P/S': 0,
        'P/E': 0,
        'P/B': 0,
        'Profit Margin(%)': 0,
        'ROE(%)': 0,
        'Current Ratio': 0
    }

    # 获取基础财务数据
    quarterly_financials = ticker.quarterly_financials
    quarterly_balance_sheet = ticker.quarterly_balance_sheet
    balance_sheet = ticker.balance_sheet if hasattr(ticker, 'balance_sheet') else None

    # 处理市值与货币转换
    try:
        currency = ticker.info.get('currency', '').replace('GBp', 'GBP')
        financial_currency = ticker.info.get('financialCurrency', currency)
        market_cap = ticker.info.get('marketCap', 0)
        if currency != financial_currency and market_cap != 0:
            market_cap = c.convert(market_cap, currency, financial_currency)
    except:
        market_cap = 0

    # 提取营收、净利润
    total_revenue = quarterly_financials.loc['Total Revenue'].iloc[-1] if 'Total Revenue' in quarterly_financials.index else 0
    net_income = quarterly_financials.loc['Net Income'].iloc[-1] if 'Net Income' in quarterly_financials.index else 0

    # 提取流动资产、流动负债
    total_current_assets = 0
    total_current_liabilities = 0
    if quarterly_balance_sheet is not None and 'Total Current Assets' in quarterly_balance_sheet.index:
        total_current_assets = quarterly_balance_sheet.loc['Total Current Assets'].iloc[-1]
        total_current_liabilities = quarterly_balance_sheet.loc['Total Current Liabilities'].iloc[-1]
    elif balance_sheet is not None and 'Total Current Assets' in balance_sheet.index:
        total_current_assets = balance_sheet.loc['Total Current Assets'].iloc[-1]
        total_current_liabilities = balance_sheet.loc['Total Current Liabilities'].iloc[-1]

    # 提取总资产、总负债
    total_assets = 0
    total_liabilities = 0
    if quarterly_balance_sheet is not None and 'Total Assets' in quarterly_balance_sheet.index:
        total_assets = quarterly_balance_sheet.loc['Total Assets'].iloc[-1]
        total_liabilities = quarterly_balance_sheet.loc['Total Liab'].iloc[-1]
    elif balance_sheet is not None and 'Total Assets' in balance_sheet.index:
        total_assets = balance_sheet.loc['Total Assets'].iloc[-1]
        total_liabilities = balance_sheet.loc['Total Liab'].iloc[-1]

    # 计算各项指标
    result['Company'] = ticker.info.get('longName', '')
    if total_revenue != 0:
        result['P/S'] = round(market_cap / total_revenue, 2)
        result['Profit Margin(%)'] = round((net_income / total_revenue)*100, 2)
    if net_income != 0:
        result['P/E'] = round(market_cap / net_income, 2)
    equity = total_assets - total_liabilities
    if equity != 0:
        result['P/B'] = round(market_cap / equity, 2)
        if net_income != 0:
            result['ROE(%)'] = round((net_income / equity)*100, 2)
    if total_current_liabilities != 0:
        result['Current Ratio'] = round(total_current_assets / total_current_liabilities, 2)

    return result

# 批量并行处理
tickers = ['EDF.PA', 'anto.l', 'meta', 'iag.l', 'PFE','PKG','0700.hk', 'mbg.de']
with ThreadPoolExecutor(max_workers=10) as executor:
    results = list(executor.map(process_single_ticker, tickers))

# 生成最终DataFrame
df = pd.DataFrame(results)
display(df)

2. 精简冗余代码

  • 删除无用导入:matplotlib、numpy、datetime在原代码中无实际用途,直接移除减少初始化开销。
  • 去掉原代码中TTM相关的冗余计算(若无需保留该逻辑),或简化计算步骤。

3. 优化DataFrame操作

原代码用df.at[row, ...]逐行修改DataFrame,这种操作效率极低。改为先将所有结果收集到列表,最后一次性生成DataFrame,速度可提升数倍。

4. 简化异常处理

用dict.get()、条件判断替代嵌套try-except块,既降低代码复杂度,也减少不必要的异常捕获开销。比如获取ticker.info字段时,直接用get方法设置默认值,无需嵌套try。

5. 本地缓存数据(可选)

若需多次运行脚本,可将已获取的股票数据缓存到本地文件(如用pickle),下次运行直接读取缓存,避免重复请求网络。


内容的提问来源于stack exchange,提问作者Luca Charalambides

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 03:54:30