跳到主要内容

仓位管理

仓位管理是量化交易成功的关键,它决定了风险暴露程度和资金增长曲线。

核心原则

仓位管理的目标:
1. 保护本金(生存第一)
2. 优化收益风险比
3. 控制回撤在可接受范围
4. 充分利用资金效率

基础仓位模型

固定金额法

import numpy as np
import pandas as pd

class FixedDollarSizing:
"""
固定金额仓位管理

每笔交易投入固定金额
"""

def __init__(self, capital_per_trade=10000):
self.capital_per_trade = capital_per_trade

def calculate_position(self, price, **kwargs):
"""
计算仓位规模

price: 当前价格
"""
shares = int(self.capital_per_trade / price)
return shares

def calculate_dollar_exposure(self, price, shares):
"""计算美元敞口"""
return price * shares

固定比例法

class FixedFractionalSizing:
"""
固定比例仓位管理

每笔交易使用账户固定百分比的资金
"""

def __init__(self, account_value, risk_percent=0.02):
self.account_value = account_value
self.risk_percent = risk_percent

def calculate_position(self, entry_price, stop_loss_price, **kwargs):
"""
计算仓位规模

entry_price: 入场价格
stop_loss_price: 止损价格
"""
# 每笔交易承担的风险金额
risk_amount = self.account_value * self.risk_percent

# 每单位风险
risk_per_unit = abs(entry_price - stop_loss_price)

if risk_per_unit == 0:
return 0

# 仓位 = 风险金额 / 每单位风险
position_size = risk_amount / risk_per_unit

return position_size

def update_account_value(self, new_value):
"""更新账户价值"""
self.account_value = new_value

固定风险法

class FixedRiskSizing:
"""
固定风险仓位管理

每笔交易固定金额的风险暴露
"""

def __init__(self, account_value, fixed_risk_amount=1000):
self.account_value = account_value
self.fixed_risk_amount = fixed_risk_amount

def calculate_position(self, entry_price, stop_loss_price):
"""计算仓位"""
risk_per_share = abs(entry_price - stop_loss_price)

if risk_per_share == 0:
return 0

shares = int(self.fixed_risk_amount / risk_per_share)

# 确保不超过账户总价值的限制
max_shares = int(self.account_value * 0.5 / entry_price)

return min(shares, max_shares)

高级仓位模型

凯利公式

class KellyCriterion:
"""
凯利公式仓位管理

f* = (p * b - q) / b

其中:
p = 胜率
q = 败率 = 1 - p
b = 盈亏比(平均盈利/平均亏损)
"""

def __init__(self, win_rate, win_loss_ratio, half_kelly=True):
"""
win_rate: 历史胜率
win_loss_ratio: 平均盈利/平均亏损
half_kelly: 是否使用半凯利(更保守)
"""
self.win_rate = win_rate
self.win_loss_ratio = win_loss_ratio
self.half_kelly = half_kelly

def calculate_kelly_fraction(self):
"""计算凯利比例"""
lose_rate = 1 - self.win_rate

kelly = (self.win_rate * self.win_loss_ratio - lose_rate) / self.win_loss_ratio

# 确保结果合理
kelly = max(0, min(kelly, 1))

if self.half_kelly:
kelly = kelly / 2

return kelly

def calculate_position(self, account_value, entry_price, atr=None):
"""
计算仓位

结合凯利公式和ATR调整
"""
kelly_fraction = self.calculate_kelly_fraction()

# 基于波动率调整(可选)
if atr is not None:
vol_adjustment = 0.02 / atr # 目标日波动2%
kelly_fraction = min(kelly_fraction, vol_adjustment)

position_value = account_value * kelly_fraction
shares = int(position_value / entry_price)

return shares

@staticmethod
def estimate_from_history(returns):
"""
从历史收益估计凯利参数
"""
positive = returns[returns > 0]
negative = returns[returns < 0]

win_rate = len(positive) / len(returns)
win_loss_ratio = abs(positive.mean() / negative.mean())

return KellyCriterion(win_rate, win_loss_ratio)

最优 f 方法

class OptimalF:
"""
Ralph Vince 的最优 f 方法

基于历史交易序列优化仓位比例
"""

def __init__(self, trade_returns):
"""
trade_returns: 历史交易收益率序列
"""
self.trade_returns = trade_returns

def calculate_twr(self, f):
"""
计算总财富回报 (Terminal Wealth Relative)
"""
twr = 1
for ret in self.trade_returns:
# HPR = 1 + f * 收益率
hpr = 1 + f * ret
if hpr <= 0:
return 0 # 破产
twr *= hpr
return twr

def find_optimal_f(self, step=0.01):
"""
搜索最优 f
"""
best_f = 0
best_twr = 0

for f in np.arange(0, 1, step):
twr = self.calculate_twr(f)
if twr > best_twr:
best_twr = twr
best_f = f

return best_f, best_twr

def calculate_position(self, account_value, f, current_risk):
"""
基于最优 f 计算仓位

current_risk: 当前交易的风险(如ATR)
"""
# 最大损失 = f * 账户
max_loss = f * account_value

# 仓位 = 最大损失 / 当前交易风险
position_size = max_loss / current_risk

return position_size

波动率目标法

class VolatilityTargeting:
"""
波动率目标仓位管理

目标:保持组合波动率在目标水平
"""

def __init__(self, target_volatility=0.15, lookback=60):
"""
target_volatility: 目标年化波动率(默认15%)
lookback: 波动率计算回望期
"""
self.target_volatility = target_volatility
self.lookback = lookback

def calculate_position_scalar(self, returns):
"""
计算仓位乘数

波动率越高,仓位越低
"""
# 计算历史波动率(年化)
current_vol = returns.iloc[-self.lookback:].std() * np.sqrt(252)

if current_vol == 0:
return 1.0

# 仓位乘数 = 目标波动率 / 当前波动率
scalar = self.target_volatility / current_vol

# 限制最大杠杆
return min(scalar, 3.0)

def calculate_position(self, account_value, price, returns, signal_strength=1.0):
"""
计算仓位
"""
# 基础仓位(等权重)
base_position = account_value * signal_strength / price

# 波动率调整
vol_scalar = self.calculate_position_scalar(returns)

# 最终仓位
final_position = base_position * vol_scalar

return final_position

def inverse_volatility_weights(self, returns_df):
"""
逆波动率权重(多资产组合)

波动率越低的资产,权重越高
"""
# 计算各资产的波动率
vols = returns_df.iloc[-self.lookback:].std() * np.sqrt(252)

# 逆波动率
inv_vols = 1 / vols

# 归一化
weights = inv_vols / inv_vols.sum()

return weights

动态仓位调整

class DynamicPositionSizing:
"""
动态仓位调整

根据市场状态调整仓位
"""

def __init__(self, base_position=0.1):
self.base_position = base_position

def market_regime_adjustment(self, current_drawdown):
"""
根据回撤调整仓位

回撤越大,仓位越低
"""
if current_drawdown > -0.15: # 回撤小于15%
return 1.0
elif current_drawdown > -0.20: # 回撤15-20%
return 0.7
elif current_drawdown > -0.25: # 回撤20-25%
return 0.5
else: # 回撤超过25%
return 0.3

def correlation_adjustment(self, correlations):
"""
根据相关性调整仓位

相关性上升时降低仓位
"""
avg_correlation = np.mean(correlations)

# 相关性越高,仓位越低
adjustment = 1 - avg_correlation

return max(adjustment, 0.3)

def performance_adjustment(self, recent_performance, lookback=20):
"""
根据近期表现调整仓位

连续亏损时降低仓位
"""
if len(recent_performance) < lookback:
return 1.0

# 计算近期胜率
win_rate = (recent_performance > 0).mean()

# 胜率低于阈值时降低仓位
if win_rate < 0.4:
return 0.7
elif win_rate < 0.3:
return 0.5

return 1.0

def calculate_final_position(self, base_size, drawdown, correlations, recent_perf):
"""计算最终仓位"""
adj1 = self.market_regime_adjustment(drawdown)
adj2 = self.correlation_adjustment(correlations)
adj3 = self.performance_adjustment(recent_perf)

final_size = base_size * adj1 * adj2 * adj3

return final_size

组合层面仓位管理

class PortfolioHeatManagement:
"""
组合热力管理

控制总风险敞口
"""

def __init__(self, max_heat=0.06, max_positions=10):
"""
max_heat: 最大热力(总风险百分比)
max_positions: 最大持仓数量
"""
self.max_heat = max_heat
self.max_positions = max_positions

def calculate_heat(self, positions, stop_losses):
"""
计算当前热力

热力 = Σ(仓位 × 每单位风险)
"""
total_heat = 0
for pos, stop in zip(positions, stop_losses):
risk_per_unit = abs(pos['entry'] - stop)
heat = pos['size'] * risk_per_unit / pos['account_value']
total_heat += heat

return total_heat

def can_add_position(self, current_heat, new_position_heat):
"""检查是否可以添加新仓位"""
return current_heat + new_position_heat <= self.max_heat

def scale_positions(self, positions, target_heat):
"""
按比例调整仓位以达到目标热力
"""
current_heat = self.calculate_heat(positions, [p['stop'] for p in positions])

if current_heat == 0:
return positions

scale_factor = target_heat / current_heat

for pos in positions:
pos['size'] *= scale_factor

return positions

金字塔加仓

class Pyramiding:
"""
金字塔加仓策略

盈利时逐步加仓
"""

def __init__(self, max_units=4, atr_multiplier=0.5):
self.max_units = max_units
self.atr_multiplier = atr_multiplier

def calculate_add_on_points(self, entry_price, atr, direction=1):
"""
计算加仓点

每上涨 N 个 ATR 加仓一次
"""
add_on_points = []
for i in range(1, self.max_units):
if direction == 1: # 多头
point = entry_price + i * self.atr_multiplier * atr
else: # 空头
point = entry_price - i * self.atr_multiplier * atr
add_on_points.append(point)

return add_on_points

def calculate_unit_size(self, base_size, unit_number):
"""
计算每单位规模

金字塔:越往后规模越小
"""
# 递减加仓
return base_size * (1 - unit_number * 0.1)

def should_add(self, current_price, last_add_price, atr, direction=1):
"""判断是否应该加仓"""
if direction == 1:
return current_price >= last_add_price + self.atr_multiplier * atr
else:
return current_price <= last_add_price - self.atr_multiplier * atr

实际应用示例

def position_sizing_example():
"""仓位管理综合示例"""

account_value = 100000
entry_price = 100
stop_loss = 95
atr = 2.5
historical_returns = pd.Series(np.random.randn(100) * 0.02)

# 1. 固定比例法
fixed_frac = FixedFractionalSizing(account_value, risk_percent=0.02)
pos1 = fixed_frac.calculate_position(entry_price, stop_loss)
print(f"固定比例仓位: {pos1:.2f} 股")

# 2. 凯利公式
kelly = KellyCriterion(win_rate=0.55, win_loss_ratio=2.0, half_kelly=True)
pos2 = kelly.calculate_position(account_value, entry_price, atr)
print(f"凯利仓位: {pos2:.2f} 股")

# 3. 波动率目标
vol_target = VolatilityTargeting(target_volatility=0.15)
pos3 = vol_target.calculate_position(account_value, entry_price, historical_returns)
print(f"波动率目标仓位: {pos3:.2f} 股")

# 4. 动态调整
dynamic = DynamicPositionSizing(base_position=0.1)
final_pos = dynamic.calculate_final_position(
base_size=pos1,
drawdown=-0.10,
correlations=[0.3, 0.4, 0.2],
recent_perf=historical_returns
)
print(f"动态调整后仓位: {final_pos:.2f} 股")

注意事项

仓位管理黄金法则:

1. 永远不要用账户的100%去冒险
2. 单笔交易风险不超过2%
3. 总风险敞口(热力)不超过6%
4. 使用半凯利或更保守的仓位
5. 在市场不确定性高时降低仓位
6. 连续亏损时主动减仓
7. 不同策略使用不同的仓位管理规则

延伸阅读