4、Python基础速通(下):条件判断与循环、函数定义与使用、文件读写操作、异常处理

好,咱们接着上节课的内容往下走。上回我们把Python的数据类型和运算符捋了一遍,算是把"食材"备齐了。今天这堂课,咱们要开始真正"炒菜"了——也就是控制程序的执行流程、封装可复用的逻辑、跟文件打交道,以及处理那些让人头疼的异常情况。

我个人觉得,这四块内容是量化交易脚本里最常用的基本功。你想想看,一个策略无非就是:判断条件是否满足 → 循环处理数据 → 调用函数执行逻辑 → 读写配置文件或日志 → 遇到错误别崩盘。嗯,就是这么回事。

Python基础速通(下) 条件判断与循环 if/elif/else, for, while 函数定义与使用 def, 参数, 返回值, lambda 文件读写操作 open, read, write, with 异常处理 try/except/finally, raise

4.1 条件判断:让程序学会"看情况办事"

量化交易里最核心的逻辑是什么?说白了就是"如果A成立,就做B;否则做C"。比如:如果5日均线上穿20日均线,就买入;否则空仓观望。这就是条件判断的典型应用。

Python的条件判断用 ifelifelse 来实现。语法很简单,但有几个坑我得提前跟你说。

# 基础结构
price = 10.5
if price > 10:
    print("价格高于10元,考虑卖出")
elif price < 8:
    print("价格低于8元,考虑买入")
else:
    print("价格在8-10之间,持有观望")

# 注意:Python用缩进来表示代码块,不是花括号!
# 我见过太多新手在这里翻车了
⚠️ 避坑指南
我曾经在写一个回测脚本时,因为 ifelif 的顺序搞反了,导致策略信号全部错乱。记住:if 从上往下判断,一旦满足某个条件,后面的 elifelse 就不再执行了。所以要把最严格的条件放在最前面。

还有一个常用的技巧——三元表达式。适合简单的二选一场景:

# 传统写法
if volume > 10000:
    status = "活跃"
else:
    status = "不活跃"

# 三元表达式(一行搞定)
status = "活跃" if volume > 10000 else "不活跃"

4.2 循环:批量处理数据的利器

做量化交易,你经常要处理成千上万条K线数据。一条条写代码?那得写到猴年马月。这时候就需要循环出马了。

Python有两种循环:forwhile。我个人90%的场景都用 for,因为它更直观、更安全。

# for循环:遍历列表
prices = [10.2, 10.5, 10.3, 10.8, 10.1]
for price in prices:
    print(f"当前价格: {price}")

# 带索引的遍历(用enumerate)
for i, price in enumerate(prices):
    print(f"第{i+1}根K线,价格: {price}")

# while循环:条件满足就一直跑
balance = 10000
while balance > 0:
    trade_loss = 500
    balance -= trade_loss
    print(f"交易亏损,剩余资金: {balance}")
print("爆仓了...")
💡 我的经验
写循环时一定要小心死循环。我有个同事曾经在while循环里忘了更新条件变量,结果程序跑了一整夜,把服务器CPU干到100%。嗯,第二天他就被约谈了。
建议:能用 for 就别用 while,除非你真的需要无限循环(比如实时行情推送)。

循环里还有两个控制语句:break(跳出整个循环)和 continue(跳过本次循环)。

# break示例:找到第一个满足条件的就停
for price in prices:
    if price > 10.5:
        print(f"找到目标价格: {price}")
        break  # 找到了,后面的不用看了

# continue示例:跳过不符合条件的数据
for price in prices:
    if price < 10.0:
        continue  # 低于10块的跳过,不处理
    print(f"处理价格: {price}")

4.3 函数定义与使用:把逻辑"打包"起来

你想想看,如果每次计算均线都要写一遍循环,那代码得多臃肿?函数就是用来解决这个问题的——把一段逻辑封装起来,起个名字,随用随调。

# 定义一个计算移动平均线的函数
def calculate_ma(prices, window=5):
    """
    计算移动平均线
    :param prices: 价格列表
    :param window: 窗口大小,默认5
    :return: 移动平均值列表
    """
    ma_list = []
    for i in range(len(prices)):
        if i < window - 1:
            ma_list.append(None)  # 前几个数据不够,填None
        else:
            avg = sum(prices[i-window+1:i+1]) / window
            ma_list.append(avg)
    return ma_list

# 调用函数
prices = [10, 11, 12, 13, 14, 15, 16]
ma5 = calculate_ma(prices, window=5)
print(f"5日均线: {ma5}")

这里有几个要点:

  • 参数默认值window=5 表示如果不传这个参数,默认用5。我在项目中经常用这个特性,让函数更灵活。
  • 文档字符串:函数开头的三引号注释,方便别人(包括未来的你)理解函数用途。
  • 返回值:用 return 把结果传出来。没有 return 的函数默认返回 None
🔑 关键原则:函数只做一件事
一个好的函数应该只负责一个功能。比如:计算均线的函数就别在里面画图,画图另写一个函数。这样代码好维护,也好测试。

另外,Python还支持匿名函数(lambda),适合写一些简单的、一次性使用的逻辑:

# lambda示例:对价格列表排序
prices = [10.5, 8.2, 12.1, 9.8]
# 按价格降序排序
sorted_prices = sorted(prices, key=lambda x: -x)
print(sorted_prices)  # [12.1, 10.5, 9.8, 8.2]

4.4 文件读写操作:让数据"持久化"

程序跑完,数据就丢了?那可不行。量化交易里,你要把策略参数、交易日志、回测结果都保存下来。文件读写就是干这个的。

Python内置的 open() 函数是文件操作的入口。我强烈建议你用 with 语句,它会自动帮你关闭文件,省心又安全。

# 写入文件
with open("trade_log.txt", "w", encoding="utf-8") as f:
    f.write("2024-01-01, 买入, 100股, 价格10.5\n")
    f.write("2024-01-02, 卖出, 100股, 价格11.2\n")
# 文件自动关闭,不用操心

# 读取文件
with open("trade_log.txt", "r", encoding="utf-8") as f:
    content = f.read()  # 一次性读取全部
    print(content)

# 逐行读取(适合大文件)
with open("trade_log.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())  # strip()去掉换行符
模式 说明 常用场景
'r' 只读模式 读取配置文件、历史数据
'w' 写入模式(覆盖) 保存新的日志、结果
'a' 追加模式 持续记录交易日志
'r+' 读写模式 需要同时读写的场景
⚠️ 注意编码问题
读写中文文件时,一定要指定 encoding="utf-8"。我曾经在Windows上写了一个策略,没指定编码,结果换到Linux服务器上跑,中文全变成乱码了。排查了半天才发现是编码问题。

4.5 异常处理:让程序"摔倒了还能爬起来"

程序跑着跑着,突然遇到网络断开、文件不存在、数据格式不对……然后就崩溃了?这在实际交易中是不能接受的。异常处理就是给程序穿上"防弹衣"。

# 基本结构:try-except
try:
    price = float(input("请输入价格: "))
    result = 100 / price
    print(f"计算结果: {result}")
except ValueError:
    print("输入的不是有效数字,请重新输入")
except ZeroDivisionError:
    print("价格不能为0,请重新输入")
except Exception as e:
    print(f"发生了未知错误: {e}")
else:
    print("没有发生异常,正常执行")
finally:
    print("无论是否异常,这行都会执行")

为什么要有 finally?你想想看,如果程序在读取文件时出错了,但文件已经打开了,这时候需要关闭文件。finally 就是用来做这种"善后工作"的。

💡 我的建议
不要滥用异常处理。只捕获你预期可能发生的异常,并且给出有意义的提示信息。我曾经见过有人写 except: pass,把所有异常都吞掉了,结果程序出了bug完全不知道,数据全错了还在跑。那叫掩耳盗铃。

你还可以主动抛出异常,用于校验参数:

def trade(stock_code, quantity):
    if not isinstance(stock_code, str) or len(stock_code) != 6:
        raise ValueError("股票代码必须是6位字符串")
    if quantity <= 0:
        raise ValueError("交易数量必须大于0")
    print(f"正在交易: {stock_code}, 数量: {quantity}")

# 调用
try:
    trade("600519", 100)  # 正确
    trade("123", -5)      # 会抛出异常
except ValueError as e:
    print(f"交易参数错误: {e}")

好了,以上就是Python基础速通的下半部分。这四块内容——条件判断、循环、函数、文件操作、异常处理——是写量化交易脚本的"四梁八柱"。你把这些练熟了,后面写策略框架、回测引擎、实盘接口的时候,就会感觉游刃有余。

记住:代码是写给人看的,顺便让机器执行。所以写的时候多想想"别人能不能看懂"、"半年后的我自己能不能看懂"。嗯,就这样,去练练手吧。


专注资料整理