3、Python基础速通(二):条件判断与循环、函数定义与使用、文件读写操作、异常处理
好,咱们接着往下走。上一章我们把 Python 的“砖块”——变量、数据类型、运算符——都码整齐了。这一章,我们要开始搭“脚手架”了。说白了,就是让代码学会做决定、重复干活、自己封装技能,以及处理意外。
这四块内容,是任何量化策略代码的骨架。你想想看,一个交易系统不就是:
“如果价格突破均线,就买入;否则就等待。”
“每天收盘后,重复执行一遍持仓检查。”
“把计算好的信号,写到一个文件里存起来。”
“如果网络断了,别崩溃,等会儿重试。”
嗯,就是这么回事。咱们一个一个来啃。
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("卖出信号")
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: 捕获了,结果程序一直不报错,但数据全是错的。后来我改成只捕获具体的异常类型(比如 ValueError、ConnectionError),其他异常让它直接崩溃,反而更容易发现问题。
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 的数据分析库,到时候这些基础都会派上用场。