⚠ 交易存在重大亏损风险。本网站的所有内容仅供教育用途,不构成财务建议。
第 2 课,共 13 课 · 免费

一课掌握金融所需的 Python 基础:数据类型、列表、字典、循环、函数与错误信息

学习交易者所需的最少核心 Python 知识:数字、字符串、列表、字典、循环、函数,以及如何阅读回溯信息(traceback)。

作者: Moustafa Hijazi内容审核日期: 2026-10-30阅读约 7 分钟自学课程

你将学到什么

  • 你在价格数据中会遇到的数据类型:int、float、str、bool、None 和 datetime。
  • 列表和字典如何存储交易清单,以及 for 循环如何处理它。
  • 如何编写带有文档字符串和默认参数的函数,以及为什么函数能让回测变得可测试。
  • 如何自下而上阅读 Python 回溯信息,并修复五种最常见的错误。

讲解

类型。Python 中的每个值都有一个类型。42 是 int(整数),42.5 是 float(以二进制存储的小数),"AAPL" 是 str(文本),True 是 bool,而 None 表示“没有值”。浮点数是近似值(0.1 + 0.2 会输出 0.30000000000000004),因此永远不要用 == 比较它们;请使用 round() 或一个容差。日期请使用 pandas 时间戳(第 3 课)。

列表是用方括号书写的有序集合:closes = [100.0, 102.0, 101.5]。索引从零开始(closes[0] 是 100.0),负索引从末尾倒数(closes[-1] 是最新的收盘价),而切片 closes[1:3] 返回元素 1 和 2,但不包括 3。同样的“不含终点”规则也适用于 pandas 的 iloc。

字典把键映射到值:trade = {"symbol": "AAA", "entry": 50.0, "qty": 100}。用 trade["entry"] 访问;缺失的键会引发 KeyError,而 trade.get("fee", 0.0) 会返回一个默认值。

循环与条件。for 循环会依次访问每个元素:for t in trades: 后面跟一个缩进的代码块。缩进(四个空格)决定了代码块的范围。if、elif 和 else 根据条件进行分支,比较运算符有 ==、!=、<、>=。

函数把逻辑封装起来,以便复用和测试。关键字 def 开始一个定义,参数放在括号中,return 把值返回:

def r_multiple(entry, exit_price, stop, side="long"):

'''返回以初始风险(R)为单位的盈亏。'''

risk = abs(entry - stop)

pnl = exit_price - entry if side == "long" else entry - exit_price

return pnl / risk

三引号字符串是文档字符串(docstring,即说明文档),side="long" 是一个默认参数。让函数保持短小、明确其输入且没有副作用;正是这一点让第 9 课能够对它们进行单元测试。

阅读错误信息。出错时,Python 会打印一段回溯信息(traceback)。先读最后一行:它给出错误类型和错误消息。然后看它上方的那一行,那里显示错误发生在你代码中的哪个位置。最常见的错误有:NameError(你在定义变量之前就使用了它,常见原因是某个笔记本单元格没有运行);TypeError(例如把来自 CSV 文件的字符串与数字相加,用 float() 修复);KeyError(某个列名或字典键的拼写不同,检查空格和大小写);IndexError(你在一个只有 10 个元素的列表中索取第 10 个元素,记住索引从零开始);以及 ZeroDivisionError(止损价等于入场价时风险为零)。

实例演算

假设示例:三笔已平仓的多头交易,均以欧元计,不计佣金和税费。

trades = [

{"symbol": "AAA", "entry": 50.0, "exit": 53.0, "stop": 48.0, "qty": 100},

{"symbol": "BBB", "entry": 20.0, "exit": 19.0, "stop": 19.0, "qty": 250},

{"symbol": "CCC", "entry": 80.0, "exit": 78.0, "stop": 76.0, "qty": 60},

]

total = 0.0

for t in trades:

pnl = (t["exit"] - t["entry"]) * t["qty"]

r = r_multiple(t["entry"], t["exit"], t["stop"])

total += pnl

print(t["symbol"], pnl, round(r, 2))

print("Total:", total)

AAA 盈利 = (53 − 50) × 100 = €300;每股风险 €2,因此 R = 3 ÷ 2 = 1.5。BBB = (19 − 20) × 250 = −€250;每股风险 €1,R = −1.0(恰好被止损)。CCC = (78 − 80) × 60 = −€120;风险 €4,R = −0.5。合计 = 300 − 250 − 120 = −€70。输出各行:AAA 300.0 1.5、BBB -250.0 -1.0、CCC -120.0 -0.5、Total: -70.0。

total += pnl 是 total = total + pnl 的简写。三笔交易无法说明一种方法的好坏;这里的重点是运作机制。

常见错误

不按顺序运行笔记本单元格笔记本允许以任意顺序运行单元格。修改了 trades 列表却只重新运行循环单元格,一个过时的值就会悄无声息地进入结果;而在内核重启之后,你则会得到 NameError。在相信任何数字之前,请使用“Restart kernel and run all cells”(重启内核并运行所有单元格),确保它能从上到下无错误地运行完毕。

练习活动

在纸上编写一个函数 position_size(account, risk_pct, entry, stop),它返回整数股数(向下取整),并在止损价等于入场价时引发一个清晰的 ValueError。然后写出账户 €8,000、风险 1.25%、入场价 €32.50、止损价 €30.00 时的结果。最后,说出如果你用 entry="32.50"(一个字符串)调用该函数且没有转换类型,Python 会引发哪种错误类型。

显示答案

def position_size(account, risk_pct, entry, stop):

per_share = abs(entry - stop)

if per_share == 0:

raise ValueError("止损价必须与入场价不同")

return int(account * risk_pct // per_share)

数字:风险预算 = 8,000 × 0.0125 = €100;每股风险 = 32.50 − 30.00 = €2.50;100 ÷ 2.50 恰好等于 40 股,因此函数返回 40(计划风险 €100,仓位价值 €1,300)。

使用 entry="32.50" 时,表达式 "32.50" - 30.0 会引发 TypeError: unsupported operand type(s) for -: 'str' and 'float'。请用 float(entry) 进行转换。

局限性:该函数忽略了最小交易单位、佣金,以及跳空可能造成超过计划 €100 的亏损这一事实。

要点回顾

  • 浮点数是近似值,索引从零开始,切片不含终点;这三个事实可以避免大多数初学者的错误。
  • 在使用 pandas 之前,由字典组成的列表是存放交易记录的自然形式;循环负责处理它,函数为它提供可复用的逻辑。
  • 编写带文档字符串的短小纯函数;它们就是你将在第 9 课中测试的单元。
  • 自下而上阅读回溯信息,并在相信笔记本结果之前先重启并运行全部单元格。

下一步

第 3 课介绍 pandas:Series、DataFrame、DatetimeIndex、选择和筛选行,以及用 resample 把日线转换为周线。

自测

回答问题后核对答案。你可以随意重试多次。

1. 给定 closes = [100.0, 102.0, 101.5, 103.0],closes[1:3] 返回什么?

2. 遍历交易清单的循环因 KeyError: 'Exit' 而崩溃。最可能的原因和修复方法是什么?

3. 对一笔空头交易使用本课中的 r_multiple 函数:入场价 €40.00,止损价 €42.00,出场价 €35.00。它返回什么?

供您自行复习的自动自测。您的答案在浏览器中核对,我们不会查看或评估。这不是考试,也不是资格证书。

您的进度

“已完成”仅表示您将本课标记为已学完,并不是对您理解程度的测试。 学习进度和笔记仅保存在此设备的此浏览器中,而非账户中。