
简介这份资源围绕股票与期权的挑选展开面向具备一定Python与数据分析基础、希望将机器学习与量化思路落地到实盘决策的投资者与数据科学学习者。内容涵盖历史波动率推算30天乃至一年价格区间、基于Wycoff方法的牛熊判断、推荐引擎、决策预测与少量博弈论元素并配有计算器与可视化模块帮助读者搭建从数据到建议的完整分析链路。压缩包整体约325.82MB以zip形式提供内含CSS样式文件、Excel原型及若干网络采集的表格片段Excel原型是整站构建的基础Python脚本与pandas、机器学习相关代码承担分析与预测任务目录按功能模块划分便于检索。目前已有162人学习下载。读者可据此理解波动率定价、推荐逻辑与预测模型的组合方式并参考Excel原型与脚本结构复现自己的股票期权分析工具。1. 股票期权分析从选标的到算盈亏一套能跑起来的量化框架很多人做期权亏钱不是因为方向看错而是因为一开始就选错了合约。同一个看涨观点买近月虚值可能三天归零买远月平值却能扛住两周震荡同样一笔资金卖put和买call的风险敞口完全不是一个量级。股票期权分析要解决的核心问题就三个选哪只股票、选哪个合约、这个价格值不值得下手。这篇笔记不讲教科书上的Black-Scholes推导而是把我自己搭的一套分析流程拆开——从股票筛选到期权链过滤从预测性信号到盈亏计算器每一步都有可复现的代码和参数。适合已经开过期权账户、想从凭感觉下单转向系统化决策的从业者也适合刚接触期权、想先跑通一套分析框架再投钱的新手。2. 股票端筛选先找到值得配期权的标的2.1 为什么不能直接在期权链里翻合约期权是股票的衍生品标的选错了合约选得再精细也是白搭。我见过太多人打开期权链按成交量排序挑一个看起来便宜的合约就买了结果标的本身处于下跌趋势call再便宜也是归零。常见做法是先用股票端的量化指标筛出一批候选池再进入期权链做二次过滤。这一步的核心逻辑是期权策略的收益结构决定了它对标的的走势特征有不同要求。买call需要标的在到期前有足够大的上行幅度卖put需要标的不会暴跌跨式策略需要波动率放大。所以股票筛选不是简单选“好公司”而是选“走势特征匹配策略”的标的。我一般会从三个维度做初筛趋势强度、波动率水平、流动性。趋势强度用ADX或者简单的均线排列来判断波动率用ATR或者历史波动率百分位流动性看日均成交额和买卖价差。这三个维度不需要同时最优但至少要有一个维度突出否则期权策略很难找到优势。2.2 用Python拉数据并计算筛选指标下面这段代码用yfinance拉取股票数据计算趋势、波动率和流动性三个维度的指标。注意yfinance的接口偶尔会变如果报错先检查版本。import yfinance as yf import pandas as pd import numpy as np def screen_stocks(tickers, period6mo): 对候选股票列表做初筛 tickers: 股票代码列表 period: 回看周期默认6个月 返回: 包含趋势、波动率、流动性指标的DataFrame results [] for ticker in tickers: try: df yf.download(ticker, periodperiod, progressFalse) if len(df) 60: continue # 趋势强度20日均线相对60日均线的偏离度 ma20 df[Close].rolling(20).mean() ma60 df[Close].rolling(60).mean() trend_score (ma20.iloc[-1] - ma60.iloc[-1]) / ma60.iloc[-1] # 波动率20日年化历史波动率 returns df[Close].pct_change().dropna() hv20 returns.tail(20).std() * np.sqrt(252) # 流动性日均成交额百万 avg_volume df[Volume].tail(20).mean() avg_price df[Close].tail(20).mean() liquidity avg_volume * avg_price / 1e6 results.append({ ticker: ticker, trend_score: round(trend_score, 4), hv20: round(hv20, 4), liquidity_m: round(liquidity, 2), last_price: round(df[Close].iloc[-1], 2) }) except Exception as e: print(f{ticker} 数据拉取失败: {e}) continue result_df pd.DataFrame(results) return result_df.sort_values(liquidity_m, ascendingFalse) # 示例对一批科技股做初筛 tickers [AAPL, MSFT, NVDA, AMD, TSLA, META, GOOGL, AMZN] df screen_stocks(tickers) print(df.to_string(indexFalse))这段代码的逻辑说明trend_score为正表示短期均线在长期均线之上趋势偏多hv20是年化历史波动率数值越大说明近期波动越剧烈期权权利金通常也越贵liquidity_m是日均成交额低于5000万的标的期权链买卖价差往往很大不适合做策略。参数方面period可以改成1y看更长周期但太长会稀释近期趋势信号。均线周期20和60是常用组合短线可以改成10和30长线改成50和200。筛选结果出来后我一般会保留trend_score大于0、hv20在0.2到0.8之间、liquidity_m大于5000万的标的。hv20太低说明波动不够期权买方很难赚到钱hv20太高说明市场已经定价了很大波动买方容易买贵。2.3 波动率百分位判断期权贵不贵的关键指标历史波动率本身没有绝对的高低关键看它在过去一年里处于什么位置。这就是波动率百分位IV Rank的简化版。计算方法是取过去252个交易日的滚动20日历史波动率看当前值在历史分布中的百分位。def hv_percentile(ticker, lookback252): 计算当前20日历史波动率在过去lookback个交易日中的百分位 返回0-100的数值越高说明当前波动率越贵 df yf.download(ticker, period2y, progressFalse) returns df[Close].pct_change().dropna() rolling_hv returns.rolling(20).std() * np.sqrt(252) rolling_hv rolling_hv.dropna() current_hv rolling_hv.iloc[-1] percentile (rolling_hv current_hv).sum() / len(rolling_hv) * 100 return round(percentile, 1), round(current_hv, 4) # 对筛选出的标的逐个计算 for t in [AAPL, NVDA, TSLA]: pct, hv hv_percentile(t) print(f{t}: HV百分位{pct}%, 当前HV{hv})百分位低于30%说明当前波动率处于低位期权买方有优势高于70%说明波动率偏高卖方策略更合适。这个指标不是绝对的但能帮你避免在波动率高点买入期权。我自己的习惯是百分位超过60%就不做买方了宁可等回调。3. 期权链过滤从几百个合约里挑出能做的3.1 期权链的核心筛选维度股票筛完之后进入期权链。一个流动性好的标的期权链上可能有几百个合约到期日从本周到两年后行权价从深度实值到深度虚值。全看一遍不现实必须用规则过滤。我一般按四个维度筛到期日、行权价、买卖价差、未平仓量。到期日方面买方策略我倾向于选30到60天到期的合约。太近的时间价值衰减太快太远的权利金太贵、杠杆不够。卖方策略可以选更近的比如7到21天因为时间价值衰减对卖方有利。行权价方面买方选delta在0.3到0.5之间的合约卖方选delta在0.15到0.3之间的。买卖价差要小于合约价格的5%否则一进一出就亏掉一大截。未平仓量要大于500保证流动性。3.2 用代码拉取期权链并做过滤def filter_options(ticker, min_days30, max_days60, min_delta0.3, max_delta0.5, max_spread_pct0.05, min_oi500): 过滤期权链返回符合条件的call合约 stock yf.Ticker(ticker) expirations stock.options filtered [] for exp in expirations: opt_chain stock.option_chain(exp) calls opt_chain.calls # 计算到期天数 exp_date pd.to_datetime(exp) days_to_exp (exp_date - pd.Timestamp.now()).days if days_to_exp min_days or days_to_exp max_days: continue for _, row in calls.iterrows(): # 过滤delta范围 if pd.isna(row.get(delta, None)): continue if abs(row[delta]) min_delta or abs(row[delta]) max_delta: continue # 过滤买卖价差 bid row[bid] ask row[ask] if bid 0 or ask 0: continue mid (bid ask) / 2 spread_pct (ask - bid) / mid if spread_pct max_spread_pct: continue # 过滤未平仓量 if row[openInterest] min_oi: continue filtered.append({ expiration: exp, days: days_to_exp, strike: row[strike], bid: bid, ask: ask, mid: round(mid, 2), delta: round(row[delta], 3), iv: round(row[impliedVolatility], 4), oi: int(row[openInterest]), volume: int(row[volume]), spread_pct: round(spread_pct, 4) }) result pd.DataFrame(filtered) if len(result) 0: result result.sort_values(oi, ascendingFalse) return result # 示例 calls filter_options(AAPL) print(calls.head(10).to_string(indexFalse))这段代码的关键参数说明min_days和max_days控制到期日窗口30到60天是买方策略的常用区间min_delta和max_delta控制行权价范围0.3到0.5对应平值到轻度虚值max_spread_pct设为0.05表示买卖价差不超过中间价的5%min_oi设为500保证有足够的流动性。这些参数不是固定的短线交易可以把days缩短到14到30delta放宽到0.2到0.6。注意yfinance返回的期权链数据里delta和impliedVolatility字段有时候是NaN尤其是流动性差的合约。遇到这种情况直接跳过不要试图用其他字段推算数据质量不够的情况下硬算出来的delta没有参考价值。3.3 隐含波动率与历史波动率的对比筛选出合约后还要看一个关键指标IV相对于HV的溢价。如果IV明显高于HV说明期权市场定价的波动预期比实际发生的高买方可能买贵了。计算方法是把筛选出的合约的IV和标的的HV20做对比。def iv_hv_spread(ticker, calls_df): 计算期权IV与标的HV20的差值 正值表示IV高于HV期权偏贵 _, hv hv_percentile(ticker) avg_iv calls_df[iv].mean() spread avg_iv - hv return round(avg_iv, 4), round(hv, 4), round(spread, 4) avg_iv, hv, spread iv_hv_spread(AAPL, calls) print(f平均IV{avg_iv}, HV20{hv}, IV-HV{spread})如果spread大于0.1说明期权比历史波动率贵了10个百分点以上买方要谨慎。如果spread为负说明期权相对便宜买方有优势。这个指标配合波动率百分位一起看能过滤掉大部分“买贵了”的情况。4. 预测性分析用简单模型判断方向概率4.1 为什么不用复杂模型很多人一提到预测性分析就想到LSTM、Transformer但对于期权交易来说方向预测的准确率只要比50%高一点就有价值关键是盈亏比和仓位管理。我试过用复杂的深度学习模型过拟合严重实盘表现还不如简单的逻辑回归。所以这里给的是一个轻量级的预测框架用技术指标做特征用逻辑回归输出方向概率重点是可解释和可复现。4.2 特征工程与模型训练from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score def build_features(ticker, period2y): 构建预测特征动量、波动率、成交量变化 df yf.download(ticker, periodperiod, progressFalse) df[ret5] df[Close].pct_change(5) df[ret20] df[Close].pct_change(20) df[vol_ratio] df[Volume] / df[Volume].rolling(20).mean() df[hv20] df[Close].pct_change().rolling(20).std() * np.sqrt(252) df[ma_ratio] df[Close] / df[Close].rolling(50).mean() # 标签未来5天是否上涨 df[target] (df[Close].shift(-5) df[Close]).astype(int) df df.dropna() feature_cols [ret5, ret20, vol_ratio, hv20, ma_ratio] return df[feature_cols], df[target] def train_model(ticker): X, y build_features(ticker) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, shuffleFalse ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) model LogisticRegression(max_iter1000) model.fit(X_train_scaled, y_train) pred model.predict(X_test_scaled) acc accuracy_score(y_test, pred) # 输出最新一天的方向概率 latest scaler.transform(X.iloc[[-1]]) prob model.predict_proba(latest)[0][1] return acc, prob, model.coef_[0] acc, prob, coef train_model(AAPL) print(f测试集准确率: {acc:.3f}) print(f当前上涨概率: {prob:.3f}) print(f特征权重: {dict(zip([ret5,ret20,vol_ratio,hv20,ma_ratio], coef.round(3)))})这段代码的逻辑用过去5天和20天的收益率、成交量比率、20日历史波动率、价格与50日均线的比值作为特征预测未来5天是否上涨。逻辑回归的系数可以告诉你哪个特征在起主要作用。准确率能到55%以上就算不错了不要追求太高过拟合的模型实盘会打脸。参数方面test_size0.2表示用最后20%的数据做测试shuffleFalse保证时间顺序不乱。max_iter1000是逻辑回归的迭代次数如果报收敛警告可以调大。特征窗口5天和20天是常用值短线可以改成3天和10天。4.3 把预测概率转化为期权策略建议预测概率本身不能直接下单要结合盈亏比和波动率。我一般用这样的规则如果上涨概率大于0.6且IV-HV为负考虑买call如果上涨概率小于0.4且IV-HV为正考虑卖call如果概率在0.4到0.6之间不做方向性策略考虑跨式或观望。def strategy_suggestion(prob, iv_hv_spread, hv_pct): 根据预测概率和波动率指标给出策略建议 if prob 0.6 and iv_hv_spread 0: return 买入看涨期权方向波动率双重优势 elif prob 0.6 and iv_hv_spread 0: return 谨慎买入看涨期权方向有利但波动率偏贵 elif prob 0.4 and iv_hv_spread 0.1: return 卖出看涨期权方向波动率双重优势 elif prob 0.4: return 观望或轻仓卖出看涨 elif hv_pct 70: return 波动率高位考虑卖出跨式 else: return 信号不明确观望 suggestion strategy_suggestion(prob, spread, 45) print(f策略建议: {suggestion})这个规则表不是万能的但能帮你把预测信号和期权定价结合起来避免只看方向不看波动率。实际使用中我还会加入仓位管理单笔期权买方仓位不超过总资金的2%卖方不超过5%因为卖方虽然胜率高但尾部风险大。5. 盈亏计算器下单前先算清楚最坏情况5.1 期权盈亏计算的核心变量期权盈亏计算比股票复杂因为涉及到期日、行权价、权利金、隐含波动率等多个变量。一个完整的计算器要能回答到期时标的在什么价格我保本、什么价格我翻倍、什么价格我亏光。对于买方最大亏损就是权利金关键是算保本点和目标收益对应的标的涨幅。对于卖方最大收益是权利金关键是算被行权后的亏损敞口。5.2 到期盈亏计算代码def option_payoff(option_type, strike, premium, spot_range): 计算期权到期时的盈亏 option_type: call 或 put strike: 行权价 premium: 买入/卖出的权利金每股 spot_range: 标的到期价格数组 if option_type call: intrinsic np.maximum(spot_range - strike, 0) else: intrinsic np.maximum(strike - spot_range, 0) pnl intrinsic - premium return pnl def breakeven(option_type, strike, premium): 计算保本点 if option_type call: return strike premium else: return strike - premium # 示例AAPL 现价190买入行权价195的call权利金3.5 spot np.arange(170, 220, 1) pnl option_payoff(call, 195, 3.5, spot) be breakeven(call, 195, 3.5) print(f保本点: {be}) print(f标的涨到210时盈亏: {option_payoff(call, 195, 3.5, np.array([210]))[0]:.2f}) print(f标的跌到180时盈亏: {option_payoff(call, 195, 3.5, np.array([180]))[0]:.2f})这段代码计算的是到期日的静态盈亏不考虑提前平仓。保本点对call是行权价加权利金对put是行权价减权利金。实际交易中你可以在到期前任何时间平仓盈亏取决于当时的期权价格而不是到期内在价值。但到期盈亏是判断这笔交易值不值得做的基准。5.3 加入隐含波动率的动态盈亏估算到期盈亏只考虑了内在价值忽略了时间价值和波动率变化。更精确的估算需要用Black-Scholes公式反推期权理论价格。下面是一个简化版的计算用scipy的norm模块。from scipy.stats import norm def bs_price(S, K, T, r, sigma, option_typecall): Black-Scholes期权理论价格 S: 标的现价 K: 行权价 T: 到期时间年 r: 无风险利率 sigma: 隐含波动率 d1 (np.log(S/K) (r 0.5*sigma**2)*T) / (sigma*np.sqrt(T)) d2 d1 - sigma*np.sqrt(T) if option_type call: price S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2) else: price K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1) return price def dynamic_pnl(S_new, K, T_remain, r, sigma_new, entry_premium, option_typecall): 计算标的变动后的期权盈亏考虑时间价值和波动率变化 new_price bs_price(S_new, K, T_remain, r, sigma_new, option_type) return new_price - entry_premium # 示例买入AAPL 195 call权利金3.5剩余30天IV 25% # 假设标的涨到200IV不变剩余20天 pnl_dynamic dynamic_pnl(200, 195, 20/365, 0.05, 0.25, 3.5, call) print(f标的涨到200时的动态盈亏: {pnl_dynamic:.2f})这个计算器的价值在于你可以模拟不同情景下的盈亏比如标的涨了但IV下降期权价格可能不涨反跌。很多买方亏钱就是因为只看了方向没考虑IV回落。参数方面T_remain是剩余到期时间年化r是无风险利率sigma_new是新的隐含波动率。实际使用中IV的变化很难预测但你可以做敏感性分析IV下降5个百分点盈亏会变多少。6. 避坑与常见问题我踩过的五个坑6.1 坑一流动性陷阱——买卖价差吃掉利润现象筛选出一个看起来不错的合约买入后想平仓发现bid和ask差了20%一进一出亏了10%。原因只看成交量没看买卖价差。有些合约成交量很大但做市商报价很宽尤其是深度虚值或远月合约。解决在过滤条件里加上spread_pct 0.05并且优先选未平仓量大于1000的合约。如果价差还是大用限价单在中间价附近挂单不要用市价单。6.2 坑二IV高位买入——方向对了还亏钱现象标的确实涨了但买的call没怎么涨甚至跌了。原因买入时IV处于高位标的上涨的同时IV回落时间价值衰减和波动率下降抵消了内在价值的增长。解决买入前必看HV百分位超过60%就不做买方。如果非要做选delta更高的实值合约减少时间价值占比。6.3 坑三到期日选太近——时间价值衰减太快现象买入7天到期的虚值call标的横盘三天期权归零。原因近月虚值合约的时间价值衰减呈加速趋势最后一周每天衰减可能超过10%。解决买方策略选30到60天到期的合约给标的足够的运动时间。如果要做末日轮仓位控制在总资金的0.5%以内。6.4 坑四预测模型过拟合——回测漂亮实盘打脸现象用复杂模型回测准确率70%实盘连续亏损。原因特征太多、样本太少、未来函数泄露。比如用了未来数据做特征或者训练集和测试集没有按时间分割。解决特征控制在5到8个用时间序列分割shuffleFalse准确率超过60%就要怀疑过拟合。简单模型严格风控比复杂模型更可靠。6.5 坑五忽略仓位管理——一次亏损吃掉十次盈利现象卖方策略连续赚了十次小钱一次标的暴涨亏掉全部利润还倒贴。原因卖方最大收益有限最大亏损无限仓位过重时尾部风险致命。解决卖方仓位不超过总资金的5%并且用价差策略如bull put spread限制最大亏损。买方仓位不超过2%因为归零概率高。7. 进阶技巧把分析框架串成每日工作流7.1 每日检查清单与自动化脚本把前面所有步骤串起来形成一个每日运行的脚本。我自己的习惯是每天早上花15分钟跑一遍输出一份候选清单和策略建议。def daily_workflow(tickers): 每日工作流筛选股票 - 过滤期权 - 预测方向 - 输出建议 print( * 50) print(第一步股票初筛) stock_df screen_stocks(tickers) candidates stock_df[ (stock_df[trend_score] 0) (stock_df[hv20].between(0.2, 0.8)) (stock_df[liquidity_m] 5000) ] print(candidates.to_string(indexFalse)) print(\n * 50) print(第二步期权链过滤与预测) for _, row in candidates.iterrows(): ticker row[ticker] try: calls filter_options(ticker) if len(calls) 0: continue acc, prob, _ train_model(ticker) avg_iv, hv, spread iv_hv_spread(ticker, calls) hv_pct, _ hv_percentile(ticker) suggestion strategy_suggestion(prob, spread, hv_pct) print(f\n{ticker}:) print(f 模型准确率{acc:.3f}, 上涨概率{prob:.3f}) print(f IV-HV{spread:.3f}, HV百分位{hv_pct}%) print(f 建议: {suggestion}) print(f 候选合约数: {len(calls)}) except Exception as e: print(f{ticker} 分析失败: {e}) continue # 运行 daily_workflow([AAPL, MSFT, NVDA, AMD, TSLA])这个工作流脚本把股票筛选、期权过滤、方向预测、策略建议串在一起输出一份可操作的清单。实际使用中我会把结果保存到CSV方便跟踪历史信号的表现。7.2 用价差策略替代单腿降低尾部风险单腿买方归零概率高单腿卖方尾部风险大。进阶做法是用价差策略看涨时用bull call spread买平值call卖虚值call看跌时用bear put spread。价差策略降低了权利金成本也限制了最大亏损。def bull_call_spread(long_strike, short_strike, long_premium, short_premium, spot_range): 牛市看涨价差盈亏 long_pnl option_payoff(call, long_strike, long_premium, spot_range) short_pnl -option_payoff(call, short_strike, short_premium, spot_range) return long_pnl short_pnl # 示例买195 call花3.5卖205 call收1.2 spot np.arange(180, 220, 1) spread_pnl bull_call_spread(195, 205, 3.5, 1.2, spot) max_loss spread_pnl.min() max_profit spread_pnl.max() be 195 (3.5 - 1.2) print(f最大亏损: {max_loss:.2f}) print(f最大盈利: {max_profit:.2f}) print(f保本点: {be:.2f})价差策略的最大亏损是净权利金支出最大盈利是行权价差减净权利金。这个结构适合方向判断有把握但不想承担无限风险的场景。我自己的习惯是单腿买方只在IV-HV为负且概率大于0.65时做其他情况一律用价差。7.3 一个我坚持了三年的习惯每次下单前把盈亏计算器的结果截图保存包括保本点、最大亏损、目标收益对应的标的涨幅。交易结束后回头对比实际走势和当初的假设。这个习惯帮我发现了很多次“看对方向但选错合约”的问题——有时候不是方向错了是到期日太近或者行权价太远。希望帮到你。本文还有配套的精品资源点击获取