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

好,咱们接着往下走。上一章我们把 Python 的“砖块”——变量、数据类型、运算符——都码整齐了。这一章,我们要开始搭“脚手架”了。说白了,就是让代码学会做决定重复干活自己封装技能,以及处理意外

这四块内容,是任何量化策略代码的骨架。你想想看,一个交易系统不就是:
“如果价格突破均线,就买入;否则就等待。”
“每天收盘后,重复执行一遍持仓检查。”
“把计算好的信号,写到一个文件里存起来。”
“如果网络断了,别崩溃,等会儿重试。”

嗯,就是这么回事。咱们一个一个来啃。

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

3.1 条件判断:让代码学会“看脸色”

写策略的时候,最核心的就是判断。比如:“如果当前价格大于5日均线,我就买入。” 在 Python 里,这个“如果”就是 if 语句。

price = 105
ma5 = 100

if price > ma5:
    print("价格在均线上方,考虑买入")
else:
    print("价格在均线下方,观望")

我个人习惯,写 if 的时候,条件表达式尽量写得“像人话”。比如 if price > ma5 就比 if price - ma5 > 0 好读得多。

如果条件不止两个,就用 elif

signal = 2

if signal == 1:
    print("强烈买入")
elif signal == 2:
    print("温和买入")
elif signal == 3:
    print("观望")
else:
    print("卖出信号")
小技巧:Python 里没有 switch 语句(至少3.10之前没有)。多条件判断就用 if/elif/else 搞定。如果条件太多,可以考虑用字典映射,代码会更清爽。

3.2 循环:让代码学会“重复劳动”

做量化,最常干的事就是“遍历”。遍历K线数据、遍历股票列表、遍历持仓。循环就是干这个的。

3.2.1 for 循环:遍历一切

prices = [100, 102, 101, 105, 108]

for price in prices:
    print(f"当前价格: {price}")

如果想同时拿到索引和值,用 enumerate

for i, price in enumerate(prices):
    print(f"第{i+1}根K线,价格: {price}")

我在项目中遇到过一个问题:遍历一个大列表时,直接在循环里修改列表元素,结果索引全乱了。后来我学乖了,要么用 enumerate 通过索引修改,要么新建一个列表。

3.2.2 while 循环:条件控制

while 用得少一些,但某些场景很合适。比如“一直尝试连接,直到成功”:

retry_count = 0
connected = False

while retry_count < 5 and not connected:
    print(f"第{retry_count+1}次尝试连接...")
    # 模拟连接
    connected = True  # 假设成功了
    retry_count += 1
注意:while 循环一定要有“退出条件”,否则就是死循环。我曾经在回测脚本里忘写 retry_count += 1,结果程序跑了一整晚没停,CPU 直接拉满。嗯,血的教训。

3.3 函数定义与使用:封装你的“绝活”

函数是什么?说白了,就是把一段逻辑打包起来,起个名字,以后随时调用。在量化里,计算均线、计算RSI、生成交易信号,这些都是函数。

def calculate_ma(prices, window=5):
    """计算移动平均线"""
    if len(prices) < window:
        return None
    return sum(prices[-window:]) / window

# 调用
ma_value = calculate_ma([100, 102, 101, 105, 108], window=5)
print(f"5日均线: {ma_value}")

这里有几个要点:

  • 参数默认值window=5,调用时可以不传,用默认值。
  • 返回值:用 return 返回结果。没有 return 的函数,默认返回 None
  • 文档字符串:函数体第一行的字符串,说明函数功能。写给别人看,也是写给未来的自己看。

3.3.1 作用域:变量去哪儿了?

函数内部定义的变量,外面访问不到。这叫“局部变量”。反之,函数外面定义的变量,函数内部可以读取,但不能直接修改

global_var = 10

def test():
    local_var = 20
    print(global_var)  # 可以读取
    # global_var = 30  # 这样会创建一个新的局部变量,不会修改全局的

test()
# print(local_var)  # 报错!局部变量外面访问不到

如果想在函数里修改全局变量,用 global 关键字。但我建议你尽量别这么干,容易把代码搞乱。更好的做法是把变量作为参数传进去,把结果通过 return 返回来。

3.4 文件读写操作:把数据存下来

量化交易离不开文件操作。策略信号要存日志,回测结果要存CSV,配置文件要读JSON。Python 的文件操作非常直接。

3.4.1 写文件

with open("trade_log.txt", "w", encoding="utf-8") as f:
    f.write("2024-01-15, 买入, 茅台, 100股\n")
    f.write("2024-01-16, 卖出, 茅台, 100股\n")

模式 "w" 是写入,会覆盖原有内容。如果想追加,用 "a"

3.4.2 读文件

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() 去掉换行符
重点:一定要用 with 语句!它会自动帮你关闭文件。我早期写代码时,经常忘记 f.close(),结果文件句柄泄漏,程序跑几天就崩了。用 with 之后,再也没出过这个问题。

3.4.3 读写CSV(量化最常用)

import csv

# 写入
with open("prices.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["date", "open", "high", "low", "close"])
    writer.writerow(["2024-01-15", 100, 105, 99, 103])
    writer.writerow(["2024-01-16", 103, 108, 102, 107])

# 读取
with open("prices.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

3.5 异常处理:别让程序“裸奔”

写代码,出bug是常态。但程序崩溃了直接退出,这就不太优雅了。异常处理就是给程序穿上“防弹衣”。

try:
    price = float(input("请输入价格: "))
    print(f"价格的两倍是: {price * 2}")
except ValueError:
    print("输入的不是有效数字,请重新输入")
except Exception as e:
    print(f"发生了未知错误: {e}")

在量化交易里,最常见的异常场景是网络请求和文件操作:

import time

def fetch_data(url):
    max_retries = 3
    for attempt in range(max_retries):
        try:
            # 模拟网络请求
            print(f"正在获取数据... 第{attempt+1}次尝试")
            # 假设这里会抛出异常
            if attempt < 2:
                raise ConnectionError("网络不稳定")
            return {"status": "ok", "data": [100, 102, 101]}
        except ConnectionError as e:
            print(f"连接失败: {e}")
            if attempt < max_retries - 1:
                print("等待2秒后重试...")
                time.sleep(2)
            else:
                print("重试次数用尽,放弃")
                return None

result = fetch_data("https://api.example.com/data")
避坑指南:我曾经在实盘脚本里,把所有异常都用一个 except: 捕获了,结果程序一直不报错,但数据全是错的。后来我改成只捕获具体的异常类型(比如 ValueErrorConnectionError),其他异常让它直接崩溃,反而更容易发现问题。

3.5.1 finally:不管怎样都要执行

try:
    f = open("important.txt", "r")
    data = f.read()
except FileNotFoundError:
    print("文件不存在")
finally:
    print("清理工作:关闭文件等")
    # 注意:如果文件没打开成功,这里会报错,实际代码需要更严谨

finally 里的代码,不管有没有异常,都会执行。适合放“清理”操作,比如关闭文件、释放资源。

3.6 综合小案例:一个简单的交易信号记录器

把今天学的串起来,写个实用的小工具:

import csv
from datetime import datetime

def generate_signal(price, ma_short, ma_long):
    """根据双均线生成交易信号"""
    if ma_short > ma_long and price > ma_short:
        return "BUY"
    elif ma_short < ma_long and price < ma_short:
        return "SELL"
    else:
        return "HOLD"

def log_signal_to_file(signal, price, filename="signals.csv"):
    """将信号记录到CSV文件"""
    try:
        with open(filename, "a", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow([datetime.now(), price, signal])
        print(f"信号已记录: {signal} @ {price}")
    except Exception as e:
        print(f"写入文件失败: {e}")

# 模拟使用
current_price = 105
short_ma = 103
long_ma = 100

signal = generate_signal(current_price, short_ma, long_ma)
log_signal_to_file(signal, current_price)

你看,条件判断、函数、文件操作、异常处理,全用上了。这就是一个极简的量化信号记录器。虽然简单,但骨架已经有了。

好了,这一章的内容就到这。代码多敲几遍,尤其是那个综合案例,自己改改参数跑跑看。下一章我们会接触更强大的工具——Python 的数据分析库,到时候这些基础都会派上用场。


专注资料整理