9 循环语句 股价涨跌幅提醒
9.1 引言循环在批量金融数据处理中的价值
金融市场产生海量的时间序列数据——股价、成交量、收益率等。循环结构使我们能够高效地处理这些重复数据,自动执行重复性任务,是构建金融分析系统的核心工具。
理论背景:迭代与递归
从计算理论来看,循环实现了迭代(Iteration)模式: - 迭代: 通过重复执行相同操作处理数据集合 - 递归: 函数调用自身解决问题 - 对比: 循环通常更高效,递归更优雅
在金融数据处理中,迭代更为常见,因为: - 金融数据天然具有顺序性(时间序列) - 内存消耗可控(不需要递归栈) - 更容易理解和调试
9.2 For循环基础
9.2.1 语法结构
for循环用于遍历序列(列表、元组、字符串等)或其他可迭代对象。
语法: for item in iterable:
# =============================================================================
# 题目:For循环的基本遍历操作
# =============================================================================
# 本代码演示for循环的四种基本用法:
# 1. 遍历列表 - 最常见的场景,处理股票列表
# 2. 遍历字符串 - 处理股票代码
# 3. 遍历范围 - 生成索引或重复操作
# 4. 遍历字典 - 处理键值对数据
# for循环是金融数据处理中最常用的结构,必须熟练掌握
# ==================== 示例1:遍历列表 ====================
stocks = ['中信证券', '国泰君安', '海通证券'] # 定义券商股票列表
for stock in stocks: # 依次取出列表中的每个股票名称
print(f"分析股票: {stock}") # 输出当前处理的股票
# for循环会自动遍历列表,不需要手动管理索引
# ==================== 示例2:遍历字符串 ====================
code = "600519.SH" # 贵州茅台的股票代码
for char in code: # 依次取出字符串中的每个字符
print(char) # 输出当前字符
# 可以用于解析股票代码的各个部分
# ==================== 示例3:遍历范围 ====================
for i in range(5): # 生成0到4的整数序列
print(f"第{i+1}次迭代") # 输出迭代次数(从1开始计数)
# range(5)生成序列[0,1,2,3,4],不包括5
# ==================== 示例4:遍历字典 ====================
stock_info = {'name': '中信证券', 'code': '600030.SH', 'price': 24.78} # 股票信息字典
for key in stock_info: # 依次取出字典的键
print(f"{key}: {stock_info[key]}") # 输出键和对应的值
# 默认遍历字典的键,通过键访问值9.2.2 range()函数
range()生成整数序列,是循环中最常用的工具。
语法: range(start, stop, step)
# =============================================================================
# 题目:使用range函数生成各种整数序列
# =============================================================================
# 本代码演示range函数的四种常用模式:
# 1. 指定结束值 - 最简单的用法
# 2. 指定起始和结束值 - 生成特定区间
# 3. 指定步长 - 生成等差序列
# 4. 负步长 - 倒序遍历
# range函数在金融计算中用于生成索引、时间范围等
# ==================== 用法1:指定结束值(不包含) ====================
for i in range(5): # 生成0,1,2,3,4
print(f"i = {i}") # 输出: 0,1,2,3,4
# range(stop)生成0到stop-1的整数
# ==================== 用法2:指定起始和结束值 ====================
for year in range(2020, 2025): # 生成2020到2024
print(f"年份: {year}") # 输出: 2020,2021,2022,2023,2024
# range(start,stop)生成start到stop-1的整数
# 常用于遍历特定年份的财务数据
# ==================== 用法3:指定步长 ====================
for i in range(0, 10, 2): # 生成0,2,4,6,8
print(f"偶数: {i}") # 输出偶数序列
# range(start,stop,step)以步长step生成序列
# 常用于跳过某些数据或按固定间隔采样
# ==================== 用法4:负步长(倒序) ====================
for i in range(10, 0, -1): # 生成10,9,8,...,1
print(f"倒计时: {i}") # 输出递减序列
# 负步长用于倒序遍历,如从最新到最旧的数据
# ==================== 金融应用:生成工作日 ====================
import numpy as np # 导入NumPy库
dates = np.arange('2024-01-01', '2024-01-06', dtype='datetime64[D]') # 生成日期序列
print("\n2024年1月前5个工作日:") # 输出标题
for date in dates: # 遍历日期序列
print(f" {date}") # 输出每个日期
# np.arange生成日期范围,常用于时间序列分析9.3 While循环
while循环在条件为True时重复执行,适用于不确定迭代次数的情况。
语法: while condition:
# =============================================================================
# 题目:While循环模拟价格监控过程
# =============================================================================
# 本代码演示while循环的实际应用:
# 1. 简单计数 - 基础用法,理解循环机制
# 2. 价格监控模拟 - 模拟股票价格达到目标价的过程
# while循环适合处理不确定次数的重复任务
# 在金融交易中用于监控实时价格、等待特定条件触发
# ==================== 示例1:简单计数 ====================
count = 0 # 初始化计数器
while count < 5: # 当计数器小于5时持续循环
print(f"计数: {count}") # 输出当前计数值
count += 1 # 重要:更新循环变量,避免无限循环
# 循环执行5次后,count变为5,条件不再满足,退出循环
# ==================== 示例2:模拟价格监控 ====================
print("\n价格监控模拟:") # 输出标题
price = 18.00 # 初始价格
target = 20.00 # 目标价格
days = 0 # 天数计数器
while price < target: # 当价格低于目标价时持续监控
# 模拟价格变化
price += 0.50 # 每天价格上涨0.50元
days += 1 # 天数加1
print(f"第{days}天, 价格: {price:.2f}元") # 输出每日价格
# 安全措施:避免无限循环
if days > 100: # 如果监控超过100天
print("达到最大监控天数") # 输出警告
break # 强制退出循环
# break语句立即终止循环,不管条件是否满足
print(f"\n达到目标价20元, 耗时{days}天") # 输出结果
# 实际应用中,while循环常用于实时监控市场数据重要警告: while循环容易陷入无限循环,必须确保: 1. 循环条件最终会变为False 2. 循环体内有更新条件的语句 3. 添加安全措施(如最大迭代次数)
9.4 循环控制语句
9.4.1 break跳出循环
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
r_list=[0.0192,-0.0001,0.006,0.0074,-0.0127,-0.0067,0.0095,-0.0095] # 定义每日涨跌幅列表
for i in r_list: # 逐日遍历涨跌幅数据
if i<-0.01: # 判断当日跌幅是否超过1%
break # 发现跌幅超限,立即跳出循环
print('涨跌幅数据',i) # 输出触发跌幅预警时的涨跌幅值代码深度解析:
- break的执行逻辑:
- 立即跳出最内层循环
- 不执行循环体剩余代码
- 继续执行循环后的语句
- 金融应用场景:
- 止损触发: 价格触及止损位立即平仓
- 异常检测: 发现异常数据停止处理
- 目标达成: 达到盈利目标退出
- 变量作用域:
- 循环变量在循环外仍然可访问
i保持循环中的最后一个值- 这是Python的特性(不是bug)
9.4.2 continue跳过当前迭代
# =============================================================================
# 题目:使用continue语句跳过特定数据
# =============================================================================
# 本代码演示continue语句的使用:
# 场景:只处理正收益的交易日,跳过负收益日
# continue语句用于过滤不需要处理的数据
# 在金融分析中常用于筛选特定条件的数据
# ==================== 定义收益率数据 ====================
returns = [0.0192, -0.0001, 0.006, 0.0074, -0.0127, 0.0095]
# 6个交易日的收益率数据
# ==================== 只处理正收益交易日 ====================
print("正收益交易日:") # 输出标题
count = 0 # 正收益日计数器
for r in returns: # 遍历每个收益率
# 跳过负收益
if r < 0: # 如果收益率为负
continue # 跳过本次迭代剩余代码,直接进入下一次迭代
# continue之后的代码不会被执行
count += 1 # 正收益日计数加1
print(f" 第{count}个正收益日: {r:.2%}") # 输出正收益率
# :.2%格式化为百分比,保留2位小数
print(f"\n总计正收益日: {count}天") # 输出正收益日总数
# 输出: 4天(跳过了2个负收益日)
# continue只跳过当前迭代,循环继续执行9.4.3 break vs continue
| 关键字 | 作用 | 后续代码 | 循环继续 |
|---|---|---|---|
break |
跳出循环 | 不执行,从循环后继续 | 否 |
continue |
跳过本次 | 不执行,从下次迭代继续 | 是 |
9.5 循环中的else子句
Python的循环可以带else子句,在循环正常结束时执行(未被break中断)。
# =============================================================================
# 题目:循环else子句的两种执行情况
# =============================================================================
# 本代码演示循环else子句的使用:
# 1. 循环正常结束 - 执行else子句
# 2. 循环被break中断 - 不执行else子句
# else子句用于区分"正常结束"和"中断退出"两种情况
# 在金融数据验证中非常有用
# ==================== 场景1:循环正常结束 ====================
prices = [10, 11, 12, 13, 14] # 价格列表(都低于20)
for price in prices: # 遍历价格
if price > 20: # 检查是否有价格超过20
print("发现高价股票") # 发现高价
break # 跳出循环
else: # 循环未被break中断,执行else
print("所有股票价格都在合理范围") # 所有价格都合理
# 输出: "所有股票价格都在合理范围"
print("\n" + "="*50 + "\n") # 输出分隔线
# ==================== 场景2:循环被break中断 ====================
prices2 = [10, 11, 25, 13, 14] # 价格列表(包含25)
for price in prices2: # 遍历价格
if price > 20: # 检查是否有价格超过20
print("发现高价股票") # 发现高价(25)
break # 跳出循环
else: # 由于break被执行,else不会执行
print("所有股票价格都在合理范围")
# 输出: "发现高价股票" (else子句未执行)金融应用: 验证所有数据是否符合条件
# =============================================================================
# 题目:使用循环else验证数据完整性
# =============================================================================
# 本代码演示如何使用循环else进行数据验证:
# 场景:验证所有价格是否为正数
# 如果发现任何异常价格(<=0),立即中断并提示
# 如果所有价格都正常,输出验证通过的提示
# ==================== 定义价格数据 ====================
prices = [24.78, 20.15, 14.03, 22.41, 16.17] # 股票价格列表
# 所有价格都是正数
# ==================== 验证所有价格是否为正数 ====================
for price in prices: # 遍历每个价格
if price <= 0: # 检查是否有非正价格
print(f"发现异常价格: {price}") # 输出异常价格
break # 发现异常,立即中断
else: # 循环正常结束(未发现异常)
print("✓ 所有价格数据有效") # 输出验证通过信息
# 输出: "✓ 所有价格数据有效"
# 这种模式在金融数据清洗中非常常用9.6 实战案例股价涨跌幅监控
# =============================================================================
# 题目:股价涨跌幅实时监控系统
# =============================================================================
# 本代码实现一个完整的股价监控系统:
# 1. 模拟一周的股价数据
# 2. 逐日计算涨跌幅
# 3. 根据涨跌幅判断市场状态
# 4. 触发预警时自动停止监控
# 这个系统综合运用了for循环、if条件判断、break语句等核心概念
# 是实际量化交易系统的基础框架
# ==================== 导入NumPy库 ====================
import numpy as np # 导入用于生成随机数和数值计算
# ==================== 模拟一周的股价数据 ====================
np.random.seed(42) # 设置随机种子,确保结果可重现
base_price = 20.0 # 起始价格
price_changes = np.random.randn(5) * 0.5 # 生成5日价格变化(标准差0.5)
prices = base_price + np.cumsum(price_changes) # 累加变化得到价格序列
# np.cumsum计算累积和,模拟价格的随机游走
# ==================== 输出系统标题 ====================
print("=" * 60) # 输出分隔线
print("股价涨跌幅监控系统") # 输出系统名称
print("=" * 60) # 输出分隔线
# ==================== 设定预警阈值 ====================
alert_threshold = -0.01 # 跌幅超过-1%触发警报
# ==================== 逐日监控股价 ====================
for i, price in enumerate(prices, 1): # 遍历价格序列,i从1开始
# 计算涨跌幅
if i == 1: # 第一天没有前一日数据
daily_return = 0 # 涨跌幅设为0
else: # 其他天数
daily_return = (price - prices[i-2]) / prices[i-2] # 计算收益率
# prices[i-2]是前一日价格(因为enumerate从1开始,i-2才是正确的索引)
# 转换为百分比
return_pct = daily_return * 100 # 转换为百分比形式
# 判断市场状态
if daily_return < alert_threshold: # 跌幅超过阈值
status = "⚠️ 警告" # 风险警告状态
action = "考虑减仓" # 建议减仓
elif daily_return > 0.01: # 涨幅超过1%
status = "✓ 上涨" # 上涨状态
action = "继续持有" # 建议持有
else: # 正常波动范围
status = "正常" # 正常状态
action = "观望" # 建议观望
# 输出每日监控报告
print(f"\n第{i}天:") # 输出天数
print(f" 收盘价: {price:.2f}元") # 输出收盘价
print(f" 涨跌幅: {return_pct:+.2f}%") # 输出涨跌幅(+表示正号)
print(f" 状态: {status}") # 输出状态
print(f" 建议: {action}") # 输出操作建议
# 检查是否需要停止监控
if daily_return < alert_threshold: # 如果触发预警
print("\n" + "=" * 60) # 输出分隔线
print("触发风险预警,系统暂停监控") # 输出预警信息
print("=" * 60) # 输出分隔线
break # 立即停止监控
else: # 循环正常结束(未触发break)
# 循环正常结束(未触发警报)
print("\n" + "=" * 60) # 输出分隔线
print("一周监控结束,市场表现平稳") # 输出总结信息
print("=" * 60) # 输出分隔线
# for-else结构:正常结束时执行else,break中断时不执行9.7 嵌套循环
在处理二维数据(如多只股票多日收益)时,需要使用嵌套循环。
# =============================================================================
# 题目:嵌套循环统计每日上涨股票数量
# =============================================================================
# 本代码演示嵌套循环的使用:
# 场景:3只股票,5个交易日的收益率数据
# 任务:统计每个交易日有多少只股票上涨
# 嵌套循环用于处理二维数据结构(外层遍历天数,内层遍历股票)
# 这是金融数据分析中的常见模式
# ==================== 定义收益率数据 ====================
returns = [
[0.01, 0.02, -0.01, 0.03, 0.02], # 股票A的5日收益率
[0.02, -0.01, 0.03, 0.01, -0.02], # 股票B的5日收益率
[-0.01, 0.03, 0.02, -0.02, 0.01] # 股票C的5日收益率
]
# 这是一个3行5列的二维列表(矩阵)
stock_names = ['股票A', '股票B', '股票C'] # 股票名称列表
# ==================== 统计每日正收益股票 ====================
print("每日正收益股票统计:\n") # 输出标题
for day in range(5): # 外层循环:遍历5个交易日
positive_count = 0 # 正收益股票计数器
positive_stocks = [] # 正收益股票名称列表
for stock_idx in range(3): # 内层循环:遍历3只股票
ret = returns[stock_idx][day] # 获取第stock_idx只股票在第day天的收益率
# returns[stock_idx]是第stock_idx只股票的所有收益率
# [day]取出该股票在第day天的收益率
if ret > 0: # 如果收益率为正
positive_count += 1 # 计数器加1
positive_stocks.append(stock_names[stock_idx]) # 添加股票名称
# 输出当日统计结果
print(f"第{day+1}天: {positive_count}只股票上涨") # 输出上涨股票数量
print(f" 上涨股票: {', '.join(positive_stocks)}") # 输出上涨股票名称
# ', '.join()将列表元素用逗号连接成字符串性能提示: 嵌套循环时间复杂度为O(n×m),数据量大时应考虑使用NumPy向量化操作。
9.8 循环性能优化
# =============================================================================
# 题目:不同循环方法的性能对比测试
# =============================================================================
# 本代码演示四种数组相加方法的性能差异:
# 1. Python for循环 - 最慢,但最易懂
# 2. 列表推导 - 较快,更Pythonic
# 3. zip+列表推导 - 更Pythonic,代码更清晰
# 4. NumPy向量化 - 最快,推荐用于大数据
# 性能差异在大数据集上非常明显,NumPy可快数百倍
# 在量化交易中,性能优化直接影响策略回测速度
# ==================== 导入时间库 ====================
import time # 用于计时
# ==================== 生成大数据集 ====================
n = 100000 # 数据规模:10万个元素
list1 = list(range(n)) # 生成列表[0,1,2,...,99999]
list2 = list(range(n)) # 生成相同的列表
# ==================== 方法1:Python for循环(慢) ====================
start = time.time() # 记录开始时间
result_loop = [] # 存储结果
for i in range(n): # 遍历所有元素
result_loop.append(list1[i] + list2[i]) # 相加并添加到结果列表
loop_time = time.time() - start # 计算耗时
# for循环最慢,因为每次迭代都有Python解释器开销
# ==================== 方法2:列表推导(较快) ====================
start = time.time() # 记录开始时间
result_listcomp = [list1[i] + list2[i] for i in range(n)] # 列表推导
listcomp_time = time.time() - start # 计算耗时
# 列表推导比for循环快,因为内部优化
# ==================== 方法3:zip+列表推导(更Pythonic) ====================
start = time.time() # 记录开始时间
result_zip = [a + b for a, b in zip(list1, list2)] # 使用zip配对
zip_time = time.time() - start # 计算耗时
# zip函数将两个列表的元素配对,代码更清晰
# ==================== 方法4:NumPy向量化(最快) ====================
import numpy as np # 导入NumPy
arr1 = np.array(list1) # 转换为NumPy数组
arr2 = np.array(list2) # 转换为NumPy数组
start = time.time() # 记录开始时间
result_numpy = arr1 + arr2 # 直接相加(向量化操作)
numpy_time = time.time() - start # 计算耗时
# NumPy使用C语言实现向量化操作,速度极快
# ==================== 输出性能对比结果 ====================
print(f"Python循环: {loop_time:.4f}秒") # 输出循环耗时
print(f"列表推导: {listcomp_time:.4f}秒") # 输出列表推导耗时
print(f"zip方法: {zip_time:.4f}秒") # 输出zip方法耗时
print(f"NumPy向量化: {numpy_time:.4f}秒") # 输出NumPy耗时
print(f"\n最快方法比最慢快 {loop_time/numpy_time:.1f}倍") # 输出性能倍数
# 在大数据集上,NumPy通常比纯Python循环快100-1000倍
# 这就是为什么量化交易必须使用NumPy/Pandas的原因