4、Python基础速通(下):文件读写、异常处理、面向对象编程入门、常用内置模块(datetime、os)
好,咱们接着上一章继续。上一章我们把Python的变量、流程控制、函数这些基本功过了一遍。这一章,我带你搞定几个真正写量化脚本时天天要用的东西:文件读写、异常处理、面向对象编程入门,还有两个特别常用的内置模块——datetime和os。
说实话,这几个知识点在量化交易里几乎每个脚本都会碰到。你想想看,读取历史行情数据是不是要文件读写?策略跑崩了是不是要异常处理?写一个交易策略类是不是要用面向对象?处理时间戳、管理文件路径,是不是离不开datetime和os?
好,咱们一个一个来。
4.1 文件读写:跟数据文件打交道
量化交易的第一步,往往是读取数据。CSV文件、TXT文件、JSON文件……Python的文件操作非常直观。我个人习惯用with open语句,因为它会自动帮你关闭文件,省心。
4.1.1 读取文本文件
# 读取一个CSV格式的行情文件
with open('stock_data.csv', 'r', encoding='utf-8') as f:
content = f.read()
print(content[:200]) # 只打印前200个字符看看
这里有个坑,我刚开始学的时候踩过——编码问题。Windows系统默认是gbk编码,而很多金融数据文件是utf-8编码。如果不指定encoding='utf-8',读出来全是乱码。嗯,这个一定要注意。
4.1.2 逐行读取大文件
如果行情数据文件特别大(比如几年的分钟线),一次性读入内存可能会爆掉。这时候逐行读取就派上用场了。
# 逐行读取,适合大文件
with open('big_data.csv', 'r', encoding='utf-8') as f:
for line in f:
# 处理每一行数据
print(line.strip()) # strip()去掉换行符
我在处理美股历史tick数据时,一个文件经常几百MB,用逐行读取的方式,内存占用非常稳定。
4.1.3 写入文件
写入也很简单。比如你跑完一个回测,想把结果保存下来。
# 写入策略回测结果
results = [
'date,return,sharpe\n',
'2024-01-01,0.05,1.2\n',
'2024-01-02,-0.02,0.8\n'
]
with open('backtest_results.csv', 'w', encoding='utf-8') as f:
f.writelines(results)
注意模式参数:'w'是覆盖写入,'a'是追加写入。我曾经因为误用'w'模式,把辛苦跑了一天的回测结果给覆盖了……从那以后,我写文件前都会再三确认模式。
4.2 异常处理:让程序更健壮
量化交易中,程序跑着跑着突然崩溃,这是最让人头疼的。网络断了、数据格式变了、除零了……各种意外都可能发生。异常处理就是给程序穿上防弹衣。
4.2.1 try-except 基础用法
try:
# 可能出错的代码
price = float('abc') # 这行会报错
print(price)
except ValueError as e:
print(f'数据格式错误:{e}')
你看,程序不会崩溃,而是优雅地打印出错误信息,然后继续运行。
4.2.2 捕获多种异常
实际项目中,一个操作可能引发多种异常。比如读取网络数据时,可能网络断开(ConnectionError),也可能数据格式不对(ValueError)。
try:
# 从API获取行情数据
data = fetch_market_data('AAPL')
process_data(data)
except ConnectionError:
print('网络连接失败,稍后重试')
except ValueError:
print('数据格式异常,跳过该数据')
except Exception as e:
print(f'未知错误:{e}')
我个人习惯把Exception放在最后,作为兜底。这样既能精确处理已知错误,又不会漏掉未知问题。
4.2.3 finally 和 else
finally块里的代码,不管有没有异常都会执行。常用于释放资源,比如关闭数据库连接。
try:
file = open('data.csv', 'r')
data = file.read()
except FileNotFoundError:
print('文件不存在')
else:
print('文件读取成功') # 没有异常时执行
finally:
file.close() # 无论如何都要关闭文件
4.3 面向对象编程入门:把代码组织得更清晰
面向对象编程(OOP)听起来高大上,说白了就是把相关的数据和函数打包成一个“对象”。在量化交易中,一个交易策略、一个订单、一个账户,都很适合用对象来表示。
4.3.1 类和对象
类就是模板,对象就是根据模板造出来的具体实例。
class Stock:
"""股票类"""
def __init__(self, symbol, price):
self.symbol = symbol # 股票代码
self.price = price # 当前价格
def update_price(self, new_price):
self.price = new_price
print(f'{self.symbol} 价格更新为 {self.price}')
# 创建对象
aapl = Stock('AAPL', 150.0)
aapl.update_price(155.0)
__init__是构造方法,创建对象时自动调用。self代表对象本身,每个方法第一个参数都是它。
4.3.2 封装:把数据藏起来
好的设计应该把内部实现细节隐藏起来,只暴露必要的接口。在Python中,用双下划线开头的属性表示私有。
class TradingAccount:
def __init__(self, initial_balance):
self.__balance = initial_balance # 私有属性
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balance
account = TradingAccount(10000)
account.deposit(5000)
print(account.get_balance()) # 15000
# print(account.__balance) # 这行会报错
为什么要封装?你想想看,如果外部代码可以直接修改__balance,那账户余额就可能变成负数,这在交易系统中是不允许的。通过方法控制访问,可以加入校验逻辑。
4.3.3 继承:复用代码
不同的策略可能有共同的行为,比如都需要计算收益率。继承可以让我们复用这些公共代码。
class Strategy:
def __init__(self, name):
self.name = name
def calculate_return(self, start_price, end_price):
return (end_price - start_price) / start_price
class MovingAverageStrategy(Strategy):
def __init__(self, name, window):
super().__init__(name) # 调用父类构造方法
self.window = window
def generate_signal(self, prices):
# 计算移动平均线信号
pass
ma_strategy = MovingAverageStrategy('MA_20', 20)
print(ma_strategy.calculate_return(100, 110)) # 0.1
4.4 常用内置模块:datetime 和 os
这两个模块在量化交易中几乎天天用。datetime处理时间,os处理文件和路径。
4.4.1 datetime模块:时间就是金钱
量化交易中,时间戳、日期计算、时间格式转换,都是家常便饭。
from datetime import datetime, timedelta
# 获取当前时间
now = datetime.now()
print(f'当前时间:{now}')
# 格式化输出
formatted = now.strftime('%Y-%m-%d %H:%M:%S')
print(f'格式化后:{formatted}')
# 字符串转时间对象
date_str = '2024-01-15 09:30:00'
dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
print(f'转换后:{dt}')
# 时间加减
yesterday = now - timedelta(days=1)
print(f'昨天此时:{yesterday}')
我在处理美股数据时,经常需要把Unix时间戳(比如1705300000)转换成可读的日期格式。用datetime.fromtimestamp()一行搞定。
4.4.2 os模块:管理文件和路径
量化策略经常要读取多个数据文件、创建日志目录、检查文件是否存在。os模块就是干这个的。
import os
# 获取当前工作目录
cwd = os.getcwd()
print(f'当前目录:{cwd}')
# 拼接路径(自动处理不同操作系统的分隔符)
data_path = os.path.join(cwd, 'data', 'stock_data.csv')
print(f'数据文件路径:{data_path}')
# 检查文件是否存在
if os.path.exists(data_path):
print('文件存在')
else:
print('文件不存在,请检查路径')
# 创建目录
log_dir = os.path.join(cwd, 'logs')
if not os.path.exists(log_dir):
os.makedirs(log_dir) # 创建多级目录
print(f'创建目录:{log_dir}')
# 列出目录下所有CSV文件
csv_files = [f for f in os.listdir(data_path) if f.endswith('.csv')]
print(f'CSV文件列表:{csv_files}')
\,结果代码放到Linux服务器上全崩了。用os.path.join()可以自动适配不同操作系统,强烈建议养成这个习惯。
4.5 本章知识体系
下面这张图帮你梳理本章的核心知识点,方便你快速回顾。
好了,这一章的内容就到这里。文件读写让你能跟数据文件打交道,异常处理让你的程序更健壮,面向对象帮你把代码组织得更清晰,datetime和os模块则是日常开发的好帮手。这些技能在后面的量化策略实战中会反复用到,建议你多写几遍代码,形成肌肉记忆。
记住,写代码不是背语法,而是解决问题。遇到不懂的,多查官方文档,多动手试。我在刚学Python时,就是靠一遍遍敲代码、一次次踩坑,才慢慢熟练起来的。你也一样,加油。