功能说明
本代码实现基于指数期权的备兑策略(Covered Call),核心功能包括:通过持有标的指数ETF现货头寸,同时卖出虚值看涨期权获取权利金收益。策略在Backtrader框架中完成回测验证,支持动态调整行权价、到期日选择等参数配置,适用于震荡市场环境下的收益增强场景。主要风险点包含标的资产价格大幅下跌时的现货亏损、期权保证金追加风险以及流动性不足导致的平仓困难。
策略理论基础
备兑策略的核心逻辑
备兑策略通过构建"现货多头+期权空头"的组合,利用期权时间价值衰减特性获取超额收益。数学表达式为:
组合价值 = S_t + (-1) * C_t
其中S_t为标的资产价格,C_t为卖出看涨期权的价值。该策略的最大收益出现在标的资产价格等于或略高于行权价时,此时可获得全部权利金收入。
希腊字母风险控制
策略实施需重点关注以下风险指标:
- Delta: 衡量标的资产价格变动对期权价值的影响,理想状态下应维持在0.8-1.2区间
- Theta: 反映时间价值衰减速度,通常选择剩余期限7-30天的期权合约
- Vega: 波动率敏感度,当隐含波动率超过历史分位数80%时应考虑提前平仓
Backtrader框架搭建
数据管道配置
python
import backtrader as bt
from datetime import datetime
class IndexOptionData(bt.feeds.GenericCSVData):
lines = ('strike', 'expiry', 'implied_vol')
params = (
('dtformat', '%Y-%m-%d'),
('datetime', 0),
('open', 1),
('high', 2),
('low', 3),
('close', 4),
('volume', 5),
('openinterest', 6),
('strike', 7), # 行权价列索引
('expiry', 8), # 到期日列索引
('implied_vol', 9) # 隐含波动率列索引
)
策略引擎实现
python
class CoveredCallStrategy(bt.Strategy):
params = dict(
option_multiplier=100, # 每份期权对应现货数量
rebalance_days=20, # 再平衡周期
target_delta=1.0 # 目标Delta值
)
def __init__(self):
self.option_position = None
self.spot_position = None
self.rebalance_counter = 0
def next(self):
# 每日监控头寸状态
if not self.positions:
self.setup_initial_position()
return
# 到期日前三天自动平仓
current_date = self.datas[0].datetime.datetime(0)
for opt in self.option_contracts:
if (opt.p.expiry - current_date).days <= 3:
self.close_option(opt)
# 定期再平衡
self.rebalance_counter += 1
if self.rebalance_counter >= self.params.rebalance_days:
self.adjust_position()
self.rebalance_counter = 0
关键模块实现细节
期权定价模型集成
采用Black-Scholes-Merton模型进行理论价格计算,结合实时隐含波动率校正:
python
import numpy as np
from scipy.stats import norm
def bsm_price(S, K, T, r, sigma, option_type='call'):
"""改进版BSM定价函数,支持隐含波动率输入"""
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
动态行权价选择算法
python
def select_strike_price(self, underlying_price, volatility):
"""根据当前市场条件选择最优行权价"""
moneyness = underlying_price / self.params.base_strike
iv_percentile = np.percentile(self.iv_history, 70)
if volatility > iv_percentile:
# 高波动环境选择更虚值的期权
return round(underlying_price * 1.05, 2)
else:
# 低波动环境选择轻度虚值期权
return round(underlying_price * 1.02, 2)
保证金管理系统
python
class MarginCalculator:
@staticmethod
def calculate_covered_call_margin(option_price, spot_price, multiplier):
"""备兑开仓保证金计算公式"""
# 基础保证金=期权市值+现货市值*折扣系数
base_margin = option_price * multiplier + spot_price * multiplier * 0.8
# 附加波动率缓冲
vol_buffer = base_margin * 0.15
return max(base_margin, vol_buffer)
完整策略代码示例
python
# 完整策略实现文件:covered_call_strategy.py
import backtrader as bt
import pandas as pd
import numpy as np
from datetime import timedelta
class IndexOptionCoveredCall(bt.Strategy):
# 策略参数配置
params = (
('option_multiplier', 100), # 每手期权对应现货数量
('reserve_ratio', 0.1), # 现金储备比例
('max_drawdown', 0.15), # 最大回撤阈值
('stop_loss', 0.08) # 止损比例
)
def __init__(self):
# 初始化技术指标
self.ema20 = bt.indicators.ExponentialMovingAverage(period=20)
self.atr14 = bt.indicators.AverageTrueRange(period=14)
# 期权合约管理字典
self.active_options = {}
self.pending_orders = []
def log(self, txt, dt=None):
'''日志记录函数'''
dt = dt or self.datas[0].datetime.datetime(0)
print(f'{dt.isoformat()} {txt}')
def prenext(self):
# 上市首日不交易
if len(self) < 5:
return
def next(self):
current_date = self.datas[0].datetime.datetime(0)
spot_price = self.datas[0].close[0]
# 检查是否需要新开仓
if not self.positions:
self.enter_position(current_date, spot_price)
return
# 每日风险管理检查
self.perform_risk_check(spot_price)
# 处理即将到期的期权
self.handle_expiring_options(current_date)
def enter_position(self, date, spot_price):
"""建立初始头寸"""
# 买入现货ETF
cash_available = self.broker.get_cash() * (1 - self.params.reserve_ratio)
shares_to_buy = int(cash_available // spot_price)
if shares_to_buy > 0:
self.buy(size=shares_to_buy, name='SPOT')
# 卖出虚值看涨期权
strike_price = self.select_strike(spot_price)
expiry_date = self.find_next_expiry(date)
self.sell_call_option(strike_price, expiry_date)
def sell_call_option(self, strike, expiry):
"""卖出看涨期权具体实现"""
opt_data = self.get_option_data(strike, expiry)
if not opt_data:
return
# 计算合理报价
fair_premium = self.calculate_fair_premium(opt_data)
order = self.sell(dataname=opt_data,
size=self.params.option_multiplier,
price=fair_premium * 0.95, # 挂单折扣
valid=expiry - timedelta(days=1))
self.pending_orders.append(order)
def adjust_position(self):
"""头寸再平衡逻辑"""
current_value = self.broker.get_value()
target_value = current_value * 1.05 # 目标增值5%
# 现货部分调仓
spot_price = self.datas[0].close[0]
current_shares = self.positions['SPOT'].size
desired_shares = int(target_value // spot_price)
delta_shares = desired_shares - current_shares
if abs(delta_shares) > 0:
self.order_target_size(dataname=self.datas[0],
target=desired_shares)
def calculate_fair_premium(self, opt_data):
"""综合定价模型计算合理权利金"""
# BSM模型基础定价
bs_price = self.bsm_model(opt_data)
# 流动性溢价调整
liquidity_premium = self.liquidity_adjustment(opt_data)
# 波动率曲面校正
vol_surface_adj = self.vol_surface_correction(opt_data)
return bs_price * (1 + liquidity_premium) * vol_surface_adj
def risk_monitor(self):
"""实时风险监控仪表盘"""
portfolio_value = self.broker.get_value()
daily_pnl = self.broker.get_cash() - self.start_cash
max_drawdown = self.calculate_max_drawdown()
risk_report = {
'timestamp': self.datas[0].datetime.datetime(0),
'portfolio_value': portfolio_value,
'daily_pnl': daily_pnl,
'max_drawdown': max_drawdown,
'leverage': self.calculate_leverage(),
'vega_exposure': self.get_vega_exposure()
}
# 触发风控条件时发送警报
if max_drawdown > self.params.max_drawdown:
self.send_alert(f"MAX DRAWDOWN EXCEEDED: {max_drawdown:.2%}")
return risk_report