基础入门
本讲用最小样本演示空字符串、类型转换失败和除零风险如何打断收益率脚本,并通过 try/except 与条件判断做基础防护,让初学者开始建立先清洗、再计算的处理习惯。
第 7 讲开始处理 starter 系列里最常见的一类“运行时事故”。目标很明确:在计算收益率前,先挡住空值和除零这两种最容易让初学者脚本直接报错的情况。前几讲默认数据都很干净,但真实样本里,空字符串、缺失价格、上一日价格为 0 都可能出现,所以这里需要先补上一层防守。
学完这一讲后,你可以直接完成下面几件事:
try/except 做最小保护。第 7 讲的重点不是把所有异常都讲完,而是先守住最常见、最容易验证的两个坑。
如果你只在非常干净的练习样本上写代码,很容易形成一种错觉:只要公式没写错,脚本就会一直顺着跑下去。现实里并不是这样。真实数据里最常见的中断,往往不是高深模型错误,而是非常基础的脏值问题。比如:
0,收益率一除就报错。所以第 7 讲重点不在于把程序写得花哨,更在于让你的入门脚本第一次具备一点“碰到坏数据还能继续往下走”的能力。
raw_prices = [12.34, '12.80', '', 0, 13.10]
这组样本里包含三种常见情况:
12.34'12.80'''0故意把问题放进样本里,能让你更清楚地看到防护逻辑有没有生效。
这四步要解决的是两个不同层面的风险:先挡住无法转成数值的坏输入,再挡住计算阶段会让分母失效的异常值。
clean_prices = []
for item in raw_prices:
try:
clean_prices.append(float(item))
except ValueError:
print(f"跳过无法转换的值: {item}")
这一步先把明显不是数值的项挡掉。比如空字符串在转 float 时会报 ValueError,这里直接跳过即可。
print(clean_prices)
清洗后,你应该看到类似 [12.34, 12.8, 0.0, 13.1] 这样的结果。注意,空字符串已经被排除了,但 0.0 还留着,因为它是合法数值,只是后面不能作为分母。
safe_returns = []
for i in range(1, len(clean_prices)):
prev_price = clean_prices[i - 1]
curr_price = clean_prices[i]
if prev_price == 0:
print(f"跳过除零风险位置: {i}")
continue
safe_returns.append((curr_price - prev_price) / prev_price)
这里最关键的是 continue。一旦发现上一日价格为 0,就跳过这一段,而不是让整个脚本直接报错退出。
print(clean_prices)
print(safe_returns)
for ret in safe_returns:
print(f"安全收益率: {ret:.2%}")
做完这一步以后,你已经拥有了一个比前几讲更稳的小流程:先清洗,再判断,再计算。
这里的验证重点不是结果多漂亮,而是脚本有没有在碰到坏值后继续跑完,以及坏值有没有被挡在合适的位置上。
assert '' not in clean_prices
assert all(isinstance(x, float) for x in clean_prices)
如果脚本能顺利运行到最后并打印 safe_returns,就说明最基本的除零防护已经生效。
assert len(safe_returns) <= len(clean_prices) - 1
只要这些条件成立,就说明你已经把最容易让入门脚本中断的两个坑挡住了。
异常处理确实会改变程序的默认失败方式,所以更需要把“为什么跳过、跳过了什么”说清楚,而不是无声吞掉问题。
如果你是在教学样本里排查单个问题,停下来当然有价值。但如果你已经知道某类坏值是可能出现的,就应该有能力跳过它,让程序继续处理后面的样本。
因为它们处理的问题不同。try/except 主要挡“转类型时出错”,if prev_price == 0 主要挡“逻辑上不能做除法”。
不一定。真实项目里有时会记录日志、有时会补默认值。但 starter 系列先用“跳过并打印提示”最容易理解和验证。
那收益率可能是 -100%,并不一定非法。真正危险的是分母,也就是前一天价格为 0。
def calc_safe_returns(raw_prices):
clean_prices = []
for item in raw_prices:
try:
clean_prices.append(float(item))
except ValueError:
continue
returns = []
for i in range(1, len(clean_prices)):
prev_price = clean_prices[i - 1]
curr_price = clean_prices[i]
if prev_price == 0:
continue
returns.append((curr_price - prev_price) / prev_price)
return returns
print(calc_safe_returns([12.34, '12.80', '', 0, 13.10]))
这类函数虽然很小,但它让你的脚本从“只能处理完美样本”进了一步,变成“遇到明显坏值也不会立刻崩”。
量化入门里一个很重要的转折点,就是你开始意识到:不是所有数据都值得直接拿来算。第 7 讲的价值就在这里。它让你第一次主动在计算前加一道门,而不是等程序出错了再回头补救。
这种“先防守再计算”的意识,后面无论你用的是标准库、pandas 还是回测框架,都会一直有用。
如果你现在已经能挡住空值转换错误,并在上一日价格为 0 时跳过该次收益率计算,让脚本继续跑完,那第 7 讲就算完成。
本讲是《Python量化入门短课》的第 7/8 讲,当前主题是《异常处理:避开空值和除零》。
上一讲:第 6 讲《CSV读写:保存再读回价格表》。
下一讲:第 8 讲《生成一份行情摘要》。
后续安排:这是本系列最后一讲前的准备,下一讲会把前面得到的价格、收益率和上涨日结果整理成一份可读摘要。
风险揭示与免责声明
本页面内容仅用于量化研究与技术交流,旨在展示研究方法与流程,不构成对任何金融产品、证券或衍生品的要约、招揽、推荐或保证。
本文所涉历史数据、回测结果与示例参数不代表未来表现,也不应作为投资决策依据。
市场存在波动、流动性与执行偏差等不确定性,任何策略均可能出现收益波动或阶段性失效。
读者应结合自身风险承受能力进行独立判断,并在必要时咨询持牌专业机构意见。