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

Excel VBA调用Python获取Yahoo Finance现货价格失败求助

问题排查:VBA调用Python脚本无返回结果

我编写了一段通过yfinance库获取日内现货价格的Python代码,同时配套了Excel VBA代码用于调用该脚本,传入ric、datetime、tick interval三个参数获取对应价格。目前遇到的问题:单独调用Python函数能得到正确价格,但终端执行Python脚本无返回结果也无报错,VBA调用同样无法获取任何数据。


原代码参考

Python代码

import yfinance as yf
from datetime import datetime, timedelta, timezone

def get_closest_stock_price(ric, target_datetime_str, tick_interval):
    # Parse the target datetime string
    target_datetime = datetime.strptime(target_datetime_str, "%Y-%m-%d %H:%M:%S")

    # Create a new instance of yfinance Ticker for the specified Reuters ticker
    ticker = yf.Ticker(ric)

    # Download historical data
    stock_data = ticker.history(start=target_datetime - timedelta(days=1), end=target_datetime, interval=tick_interval)

    # Check if data is available
    if stock_data.empty:
        return None 

    # Make target_datetime timezone-aware using the timezone of stock_data.index
    target_datetime = target_datetime.replace(tzinfo=stock_data.index.tz)

    # Find the closest timestamp
    closest_timestamp = min(stock_data.index, key=lambda x: abs(x - target_datetime))

    # Get the stock price at the closest timestamp
    closest_price = stock_data.loc[closest_timestamp, 'Close']

    return closest_price

VBA代码

Function GetClosestStockPrice(ric As String, target_datetime As Date, tick_interval As String) As Variant
    Dim pythonScriptPath As String
    Dim pythonExePath As String
    Dim script As String
    Dim result As String

    ' Set the path to your Python script
    pythonScriptPath = "C:\xxxxx\YahooEQSpotApp\yfinance_eqspot.py"

    ' Set the path to your Python executable
    pythonExePath = "C:\Program Files\Python311\python.exe"

    ' Build the Python script command
    script = pythonExePath & " " & pythonScriptPath & " " & ric & " " & Format(target_datetime, "yyyy-mm-dd hh:mm:ss") & " " & tick_interval

    ' Run the Python script and capture the result
    result = CreateObject("WScript.Shell").Exec(script).StdOut.ReadAll

    ' Check if the result is empty
    If result = "" Then
        GetClosestStockPrice = "No data available."
    Else
        GetClosestStockPrice = CDbl(result)
    End If
End Function

测试参数与命令

  • 示例输入:ric = ^SPX,datetime = 17/01/2024 15:15:00,intervals = 15m
  • 终端执行命令:python3 yfinance_eqspot.py "^SPX" "2024-01-17 14:13:00" "15m"

核心问题与解决方案

1. 根本问题:Python脚本未处理命令行参数与输出

原Python代码仅定义了函数,但没有读取终端传入的参数、调用函数并打印结果,导致执行后无任何输出,VBA自然无法获取数据。

2. 其他潜在问题

  • 特殊字符参数(如^SPX)未加引号,终端会解析错误
  • yfinance的end参数是排他性的,目标时间刚好在边界时会漏数据
  • VBA中含空格的路径未加引号,会导致命令执行失败

修正后的代码

修正版Python代码

import yfinance as yf
from datetime import datetime, timedelta, timezone
import sys

def get_closest_stock_price(ric, target_datetime_str, tick_interval):
    # Parse the target datetime string
    target_datetime = datetime.strptime(target_datetime_str, "%Y-%m-%d %H:%M:%S")

    # Create a new instance of yfinance Ticker
    ticker = yf.Ticker(ric)

    # 调整时间范围:end加1分钟,避免目标时间刚好在边界导致数据遗漏
    stock_data = ticker.history(
        start=target_datetime - timedelta(days=1), 
        end=target_datetime + timedelta(minutes=1),
        interval=tick_interval
    )

    # Check if data is available
    if stock_data.empty:
        return None 

    # Make target_datetime timezone-aware
    target_datetime = target_datetime.replace(tzinfo=stock_data.index.tz)

    # Find the closest timestamp
    closest_timestamp = min(stock_data.index, key=lambda x: abs(x - target_datetime))

    # Get the stock price
    closest_price = stock_data.loc[closest_timestamp, 'Close']

    return closest_price

# 新增:处理命令行参数并输出结果
if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Error: 需传入3个参数:ric、target_datetime_str、tick_interval")
        sys.exit(1)
    
    ric = sys.argv[1]
    target_datetime_str = sys.argv[2]
    tick_interval = sys.argv[3]
    
    price = get_closest_stock_price(ric, target_datetime_str, tick_interval)
    print(price if price is not None else "")

修正版VBA代码

Function GetClosestStockPrice(ric As String, target_datetime As Date, tick_interval As String) As Variant
    Dim pythonScriptPath As String
    Dim pythonExePath As String
    Dim script As String
    Dim result As String
    Dim wsh As Object
    
    ' 配置路径
    pythonScriptPath = "C:\xxxxx\YahooEQSpotApp\yfinance_eqspot.py"
    pythonExePath = "C:\Program Files\Python311\python.exe"
    
    ' 为含空格的路径和特殊字符参数添加双引号,避免解析错误
    pythonExePath = """" & pythonExePath & """"
    pythonScriptPath = """" & pythonScriptPath & """"
    ric = """" & ric & """"
    target_datetime_str = """" & Format(target_datetime, "yyyy-mm-dd hh:mm:ss") & """"
    tick_interval = """" & tick_interval & """"
    
    ' 构建执行命令
    script = pythonExePath & " " & pythonScriptPath & " " & ric & " " & target_datetime_str & " " & tick_interval
    
    ' 执行脚本并捕获结果
    Set wsh = CreateObject("WScript.Shell")
    result = wsh.Exec(script).StdOut.ReadAll
    
    ' 【调试用】捕获错误输出,排查问题(调试完成后可注释)
    ' Dim errorMsg As String
    ' errorMsg = wsh.Exec(script).StdErr.ReadAll
    ' If errorMsg <> "" Then MsgBox "Python执行错误:" & errorMsg
    
    ' 处理返回结果
    If Trim(result) = "" Then
        GetClosestStockPrice = "No data available."
    Else
        GetClosestStockPrice = CDbl(result)
    End If
End Function

测试步骤

  1. 先在终端执行修正后的Python脚本,确认能输出价格:
python "C:\xxxxx\YahooEQSpotApp\yfinance_eqspot.py" "^SPX" "2024-01-17 14:13:00" "15m"
  1. 在Excel中输入公式测试:
=GetClosestStockPrice("^SPX", DATE(2024,1,17)+TIME(15,15,0), "15m")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:35:55