风险管理与资金管理
风险管理是量化交易的核心环节,决定了策略的长期生存能力。一个优秀的量化策略必须具备完善的风险控制体系。
🎯 风险管理的重要性
为什么风险管理如此重要?
- 保护本金:投资的第一原则是不亏钱,第二原则是记住第一原则
- 控制回撤:避免大幅回撤影响心态和策略执行
- 提高收益稳定性:通过风险控制获得更好的风险调整后收益
- 延长策略生命周期:避免黑天鹅事件导致策略失效
风险的类型
系统性风险
- 市场风险:整体市场下跌的风险
- 政策风险:政府政策变化带来的影响
- 宏观经济风险:经济周期、通胀等因素
非系统性风险
- 个股风险:单只股票的特有风险
- 行业风险:特定行业的风险
- 流动性风险:买卖困难的风险
操作风险
- 模型风险:策略模型失效的风险
- 技术风险:系统故障、数据错误等
- 执行风险:交易执行偏差
📊 风险指标体系
基础风险指标
1. 最大回撤 (Maximum Drawdown)
python
def calculate_max_drawdown(returns):
"""计算最大回撤"""
cumulative = (1 + returns).cumprod()
rolling_max = cumulative.expanding().max()
drawdown = (cumulative - rolling_max) / rolling_max
return drawdown.min()意义:衡量策略在历史上的最大亏损幅度 使用:通常要求最大回撤控制在15-30%以内
2. 波动率 (Volatility)
python
def calculate_volatility(returns, annualize=True):
"""计算年化波动率"""
vol = returns.std()
if annualize:
vol *= np.sqrt(252) # 年化
return vol意义:衡量收益率的离散程度 使用:波动率越低,策略越稳定
3. VaR (Value at Risk)
python
def calculate_var(returns, confidence_level=0.05):
"""计算VaR风险价值"""
return returns.quantile(confidence_level)意义:在给定置信水平下的最大预期损失 使用:95%置信度下的VaR表示5%概率下的最大损失
4. 夏普比率 (Sharpe Ratio)
python
def calculate_sharpe_ratio(returns, risk_free_rate=0.03):
"""计算夏普比率"""
excess_returns = returns.mean() - risk_free_rate/252
return excess_returns / returns.std() * np.sqrt(252)意义:风险调整后的收益指标 使用:夏普比率越高,策略性价比越好
高级风险指标
1. 卡玛比率 (Calmar Ratio)
python
def calculate_calmar_ratio(returns):
"""计算卡玛比率"""
annual_return = (1 + returns).prod() ** (252/len(returns)) - 1
max_dd = calculate_max_drawdown(returns)
return annual_return / abs(max_dd)2. 索提诺比率 (Sortino Ratio)
python
def calculate_sortino_ratio(returns, risk_free_rate=0.03):
"""计算索提诺比率"""
excess_returns = returns.mean() - risk_free_rate/252
downside_vol = returns[returns < 0].std()
return excess_returns / downside_vol * np.sqrt(252)3. Beta系数
python
def calculate_beta(returns, market_returns):
"""计算Beta系数"""
covariance = np.cov(returns, market_returns)[0][1]
market_variance = np.var(market_returns)
return covariance / market_variance🛡️ 风险控制方法
1. 仓位控制
固定仓位法
python
def fixed_position_sizing(context, target_stocks, total_position=0.8):
"""固定仓位分配"""
position_per_stock = total_position / len(target_stocks)
for stock in target_stocks:
target_value = context.portfolio.total_value * position_per_stock
order_target_value(stock, target_value)等风险仓位法
python
def equal_risk_position_sizing(context, target_stocks, target_risk=0.02):
"""等风险仓位分配"""
positions = {}
for stock in target_stocks:
# 计算股票历史波动率
vol = calculate_stock_volatility(stock)
# 根据目标风险确定仓位
position = target_risk / vol
positions[stock] = min(position, 0.2) # 单股最大20%
# 标准化仓位
total_position = sum(positions.values())
for stock in positions:
positions[stock] = positions[stock] / total_position * 0.8
order_target_percent(stock, positions[stock])凯利公式仓位法
python
def kelly_position_sizing(win_rate, avg_win, avg_loss):
"""凯利公式计算最优仓位"""
if avg_loss == 0:
return 0
win_loss_ratio = avg_win / abs(avg_loss)
kelly_fraction = win_rate - (1 - win_rate) / win_loss_ratio
# 通常使用凯利公式结果的1/4到1/2
return max(0, min(kelly_fraction * 0.25, 0.2))2. 止损策略
固定比例止损
python
def fixed_stop_loss(context, stop_loss_pct=0.08):
"""固定比例止损"""
current_data = get_current_data()
for stock in context.portfolio.positions:
position = context.portfolio.positions[stock]
current_price = current_data[stock].last_price
# 计算亏损比例
loss_pct = (position.avg_cost - current_price) / position.avg_cost
if loss_pct >= stop_loss_pct:
order_target_value(stock, 0)
log.info(f"止损卖出 {stock}, 亏损 {loss_pct:.2%}")移动止损
python
def trailing_stop_loss(context, trail_pct=0.05):
"""移动止损"""
if not hasattr(g, 'highest_prices'):
g.highest_prices = {}
current_data = get_current_data()
for stock in context.portfolio.positions:
current_price = current_data[stock].last_price
# 更新最高价
if stock not in g.highest_prices:
g.highest_prices[stock] = current_price
else:
g.highest_prices[stock] = max(g.highest_prices[stock], current_price)
# 计算止损价
stop_price = g.highest_prices[stock] * (1 - trail_pct)
if current_price <= stop_price:
order_target_value(stock, 0)
log.info(f"移动止损卖出 {stock}")
del g.highest_prices[stock]ATR止损
python
def atr_stop_loss(context, atr_multiplier=2.0):
"""ATR动态止损"""
current_data = get_current_data()
for stock in context.portfolio.positions:
# 计算ATR
atr = calculate_atr(stock, 14)
position = context.portfolio.positions[stock]
current_price = current_data[stock].last_price
# ATR止损价
stop_price = position.avg_cost - atr * atr_multiplier
if current_price <= stop_price:
order_target_value(stock, 0)
log.info(f"ATR止损卖出 {stock}")
def calculate_atr(stock, period=14):
"""计算ATR指标"""
hist_data = attribute_history(stock, period + 1, '1d',
['high', 'low', 'close'])
high_low = hist_data['high'] - hist_data['low']
high_close = abs(hist_data['high'] - hist_data['close'].shift(1))
low_close = abs(hist_data['low'] - hist_data['close'].shift(1))
true_range = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
atr = true_range.rolling(period).mean().iloc[-1]
return atr3. 止盈策略
固定比例止盈
python
def fixed_take_profit(context, profit_pct=0.20):
"""固定比例止盈"""
current_data = get_current_data()
for stock in context.portfolio.positions:
position = context.portfolio.positions[stock]
current_price = current_data[stock].last_price
# 计算盈利比例
profit_pct_actual = (current_price - position.avg_cost) / position.avg_cost
if profit_pct_actual >= profit_pct:
order_target_value(stock, 0)
log.info(f"止盈卖出 {stock}, 盈利 {profit_pct_actual:.2%}")分批止盈
python
def staged_take_profit(context):
"""分批止盈策略"""
current_data = get_current_data()
for stock in context.portfolio.positions:
position = context.portfolio.positions[stock]
current_price = current_data[stock].last_price
profit_pct = (current_price - position.avg_cost) / position.avg_cost
current_value = position.value
if profit_pct >= 0.15 and profit_pct < 0.25:
# 盈利15-25%,卖出1/3
target_value = current_value * 2/3
order_target_value(stock, target_value)
elif profit_pct >= 0.25 and profit_pct < 0.35:
# 盈利25-35%,再卖出1/3
target_value = current_value * 1/3
order_target_value(stock, target_value)
elif profit_pct >= 0.35:
# 盈利超过35%,全部卖出
order_target_value(stock, 0)4. 动态风险控制
基于波动率的仓位调整
python
def volatility_based_position(context):
"""基于波动率调整仓位"""
# 计算市场波动率
market_vol = calculate_market_volatility()
# 根据波动率调整总仓位
if market_vol > 0.25: # 高波动
target_position = 0.5
elif market_vol > 0.15: # 中等波动
target_position = 0.7
else: # 低波动
target_position = 0.9
# 调整现有持仓
current_position = context.portfolio.positions_value / context.portfolio.total_value
if current_position > target_position:
# 减仓
scale_factor = target_position / current_position
for stock in context.portfolio.positions:
current_value = context.portfolio.positions[stock].value
order_target_value(stock, current_value * scale_factor)
def calculate_market_volatility():
"""计算市场波动率"""
# 使用沪深300指数计算市场波动率
index_data = attribute_history('000300.XSHG', 30, '1d', ['close'])
returns = index_data['close'].pct_change().dropna()
return returns.std() * np.sqrt(252)回撤控制
python
def drawdown_control(context, max_drawdown=0.15):
"""回撤控制"""
if not hasattr(g, 'peak_value'):
g.peak_value = context.portfolio.total_value
current_value = context.portfolio.total_value
g.peak_value = max(g.peak_value, current_value)
# 计算当前回撤
current_drawdown = (g.peak_value - current_value) / g.peak_value
if current_drawdown >= max_drawdown:
# 触发回撤控制,清仓
for stock in list(context.portfolio.positions.keys()):
order_target_value(stock, 0)
log.info(f"触发回撤控制,当前回撤: {current_drawdown:.2%}")
# 设置恢复条件(可选)
g.recovery_mode = True
g.recovery_threshold = current_value * 1.05 # 恢复5%后重新开始交易5. 组合风险管理
相关性控制
python
def correlation_control(context, target_stocks, max_correlation=0.7):
"""控制持仓股票间相关性"""
if len(target_stocks) <= 1:
return target_stocks
# 计算股票间相关性矩阵
correlation_matrix = calculate_correlation_matrix(target_stocks)
# 贪心算法选择低相关性组合
selected_stocks = [target_stocks[0]]
for stock in target_stocks[1:]:
# 计算与已选股票的平均相关性
correlations = [correlation_matrix.loc[stock, selected]
for selected in selected_stocks]
avg_correlation = np.mean(np.abs(correlations))
if avg_correlation < max_correlation:
selected_stocks.append(stock)
if len(selected_stocks) >= 20: # 最多20只股票
break
return selected_stocks行业分散化
python
def industry_diversification(context, target_stocks, max_industry_weight=0.3):
"""行业分散化控制"""
# 获取股票行业信息
industry_dict = {}
for stock in target_stocks:
industry = get_security_info(stock).industry
if industry not in industry_dict:
industry_dict[industry] = []
industry_dict[industry].append(stock)
# 控制单个行业权重
final_stocks = []
total_value = context.portfolio.total_value
max_industry_value = total_value * max_industry_weight
for industry, stocks in industry_dict.items():
industry_stock_count = min(len(stocks),
int(max_industry_value / (total_value / len(target_stocks))))
final_stocks.extend(stocks[:industry_stock_count])
return final_stocks📈 资金管理策略
1. 资金分配方法
等权重分配
python
def equal_weight_allocation(context, target_stocks):
"""等权重资金分配"""
weight_per_stock = 1.0 / len(target_stocks)
for stock in target_stocks:
order_target_percent(stock, weight_per_stock * 0.95) # 保留5%现金市值加权
python
def market_cap_weighting(context, target_stocks):
"""按市值加权分配"""
# 获取市值数据
market_caps = {}
for stock in target_stocks:
q = query(valuation.market_cap).filter(valuation.code == stock)
df = get_fundamentals(q)
market_caps[stock] = df['market_cap'][0]
# 计算权重
total_market_cap = sum(market_caps.values())
for stock in target_stocks:
weight = market_caps[stock] / total_market_cap
order_target_percent(stock, weight * 0.95)风险平价
python
def risk_parity_allocation(context, target_stocks):
"""风险平价分配"""
# 计算各股票风险贡献
risk_contributions = {}
for stock in target_stocks:
vol = calculate_stock_volatility(stock)
risk_contributions[stock] = 1.0 / vol if vol > 0 else 0
# 标准化权重
total_risk_contribution = sum(risk_contributions.values())
if total_risk_contribution > 0:
for stock in target_stocks:
weight = risk_contributions[stock] / total_risk_contribution
order_target_percent(stock, weight * 0.95)2. 现金管理
现金缓冲策略
python
def cash_buffer_management(context, target_cash_ratio=0.05):
"""现金缓冲管理"""
current_cash_ratio = context.portfolio.available_cash / context.portfolio.total_value
if current_cash_ratio < target_cash_ratio:
# 现金不足,卖出部分持仓
reduction_ratio = (target_cash_ratio - current_cash_ratio) / (1 - current_cash_ratio)
for stock in context.portfolio.positions:
current_value = context.portfolio.positions[stock].value
new_value = current_value * (1 - reduction_ratio)
order_target_value(stock, new_value)动态现金管理
python
def dynamic_cash_management(context):
"""动态现金管理"""
# 根据市场情况调整现金比例
market_sentiment = get_market_sentiment() # 自定义市场情绪指标
if market_sentiment < -0.5: # 市场恐慌
target_cash_ratio = 0.3
elif market_sentiment < 0: # 市场悲观
target_cash_ratio = 0.15
elif market_sentiment > 0.5: # 市场乐观
target_cash_ratio = 0.02
else: # 市场中性
target_cash_ratio = 0.08
cash_buffer_management(context, target_cash_ratio)🚨 应急预案
1. 黑天鹅事件应对
python
def black_swan_protection(context):
"""黑天鹅事件保护"""
# 市场急跌保护
market_return = get_market_return_today()
if market_return < -0.05: # 大盘跌超5%
# 立即减仓50%
for stock in context.portfolio.positions:
current_value = context.portfolio.positions[stock].value
order_target_value(stock, current_value * 0.5)
log.info("触发黑天鹅保护,减仓50%")
g.black_swan_mode = True2. 系统性风险保护
python
def systematic_risk_protection(context):
"""系统性风险保护"""
# 多个指标综合判断
conditions = []
# 1. VIX恐慌指数
vix = get_vix_index()
conditions.append(vix > 30)
# 2. 连续下跌天数
consecutive_down_days = get_consecutive_down_days()
conditions.append(consecutive_down_days >= 5)
# 3. 跌停股票比例
limit_down_ratio = get_limit_down_ratio()
conditions.append(limit_down_ratio > 0.1)
# 满足2个以上条件时触发保护
if sum(conditions) >= 2:
# 全部清仓
for stock in list(context.portfolio.positions.keys()):
order_target_value(stock, 0)
log.info("触发系统性风险保护,全部清仓")
g.system_risk_mode = True📚 风险管理最佳实践
1. 制定风险预算
- 设定单笔交易最大风险不超过总资金的2%
- 单只股票持仓不超过总资金的10%
- 单个行业持仓不超过总资金的30%
- 总风险敞口不超过总资金的80%
2. 建立风险监控体系
python
def risk_monitoring(context):
"""风险监控函数"""
# 1. 持仓集中度监控
max_single_position = max([pos.value for pos in context.portfolio.positions.values()]) / context.portfolio.total_value
if max_single_position > 0.15:
log.warn(f"单股持仓过于集中: {max_single_position:.2%}")
# 2. 行业集中度监控
industry_exposure = calculate_industry_exposure(context)
max_industry_exposure = max(industry_exposure.values())
if max_industry_exposure > 0.4:
log.warn(f"行业集中度过高: {max_industry_exposure:.2%}")
# 3. 波动率监控
portfolio_vol = calculate_portfolio_volatility(context)
if portfolio_vol > 0.3:
log.warn(f"组合波动率过高: {portfolio_vol:.2%}")3. 定期风险评估
- 每周评估组合风险指标
- 每月进行压力测试
- 每季度回顾风险管理效果
- 每年更新风险管理规则
⚠️ 风险管理要点
- 风险优先:收益是不确定的,但风险是可以控制的
- 分散投资:不要把鸡蛋放在同一个篮子里
- 止损纪律:严格执行止损,不要心存侥幸
- 仓位控制:永远不要满仓,保留调整余地
- 持续监控:风险管理是动态过程,需要持续关注
风险管理是量化交易的生命线。一个没有风险管理的策略,无论历史回测多么漂亮,在实盘中都可能面临巨大损失。记住:保护本金是第一要务,盈利是第二要务。