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

使用Python实现海龟交易策略时遭遇KeyError错误求助

问题分析与解决方案

核心错误原因

你遇到的KeyError是因为DataFrame的行索引是日期类型(通过index_col='Date'设置),但你在遍历的时候用了整数i去调用data.loc[i, ...]——loc是基于标签的索引,找不到对应的整数标签就会抛出KeyError。

关键修复点

1. 正确遍历DataFrame行

改用iloc(基于整数位置的索引)来访问行,或者用enumerate(data.iterrows())同时获取位置和行数据。推荐用iloc更高效。

2. 修正ATR计算逻辑

海龟策略的真实波幅(TR)需要取三个值的最大值:

  • 当日最高价 - 当日最低价
  • 当日最高价 - 前一日收盘价
  • 前一日收盘价 - 当日最低价
    再对TR做10日移动平均得到ATR,你之前的计算方式不符合标准定义。

3. 移除多余的dropna()

计算均线时,rolling().mean()会自动在窗口不足时返回NaN,手动调用dropna()会删除这些行的对应列值,导致后续数据不完整。

修正后的完整代码

import yfinance as yf
import pandas as pd

# 下载并保存数据(可选,若已保存可注释)
start_date = '2022-01-01'
end_date = '2022-12-31'
data = yf.Ticker("ETH-USD").history(start=start_date, end=end_date, interval="1d")
data.to_csv('eth-usd.csv')

# 加载数据
pd.options.display.max_rows = 1000
data = pd.read_csv('eth-usd.csv', index_col='Date', parse_dates=True)

# 计算20日和10日移动平均线(移除多余dropna)
data['20d'] = data['Close'].rolling(20).mean()
data['10d'] = data['Close'].rolling(10).mean()

# 计算标准ATR
data['TR'] = pd.concat([
    data['High'] - data['Low'],
    abs(data['High'] - data['Close'].shift(1)),
    abs(data['Close'].shift(1) - data['Low'])
], axis=1).max(axis=1)
data['ATR'] = data['TR'].rolling(10).mean()

# 初始化参数
initial_capital = 10000
shares_to_trade = 100

# 创建仓位、盈亏、收益列
data['Position'] = None
data['P/L'] = 0.0
data['Returns'] = 0.0

# 遍历行(用iloc按位置访问)
for i in range(1, len(data)):
    # 跳过均线或ATR为NaN的行(窗口未形成)
    if pd.isna(data.iloc[i]['20d']) or pd.isna(data.iloc[i]['10d']):
        continue
    
    if data.iloc[i]['20d'] > data.iloc[i]['10d']:
        data.iloc[i, data.columns.get_loc('Position')] = 'Long'
        # 多仓的盈亏计算:当日收盘价与前日收盘价的差 × 持仓量
        data.iloc[i, data.columns.get_loc('P/L')] = shares_to_trade * (data.iloc[i]['Close'] - data.iloc[i-1]['Close'])
    elif data.iloc[i]['10d'] > data.iloc[i]['20d']:
        data.iloc[i, data.columns.get_loc('Position')] = 'Short'
        # 空仓的盈亏计算:(前日收盘价 - 当日收盘价) × 持仓量
        data.iloc[i, data.columns.get_loc('P/L')] = shares_to_trade * (data.iloc[i-1]['Close'] - data.iloc[i]['Close'])

# 计算累计收益
data['Returns'] = data['P/L'].cumsum() / initial_capital

# 绘制收益曲线
data['Returns'].plot(title='ETH-USD Turtle Strategy Returns')

额外说明

  • 修正了盈亏计算逻辑:原代码的P/L计算不符合实际交易逻辑,改成了基于当日和前日收盘价的差值来计算每日盈亏。
  • 添加了对NaN值的判断,避免在均线窗口未形成时进行仓位判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:31:31