量化学习平台
文章
市场宽度
背离图
登录
注册
增强型投资组合优化(EPO)方法研究
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问请到原文和作者交流讨论。 # 原文网址:https://www.joinquant.com/post/43949 # 标题:增强型投资组合优化(EPO)方法试用 # 作者:开心果 import numpy as np import pandas as pd from scipy.linalg import solve #初始化函数 def initialize(context): set_benchmark('000300.XSHG') set_option('use_real_price', True) set_option("avoid_future_data", True) set_slippage(FixedSlippage(0.002)) set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0.0002, close_commission=0.0002, close_today_commission=0, min_commission=5), type='fund') log.set_level('system', 'error') # 参数 g.etf_pool = [ '518880.XSHG', #黄金ETF(大宗商品) '513100.XSHG', #纳指100(海外资产) '159915.XSHE', #创业板100(成长股,科技股,题材性,中小盘) '510880.XSHG', #红利ETF(价值股,蓝筹股,防御性,中大盘) ] run_monthly(trade, 1, '10:00') #每天运行确保即时捕捉动量变化 ''' Computes the optimal portfolio allocation using the EPO method. #' #' @param x A data-set with asset returns. It should be a {tibble}, a {xts} #' or a {matrix}. #' @param signal A {double} vector with the investor's belief's (signals, forecasts). #' @param lambda A {double} with the investor's risk-aversion preference. #' @param method A {character}. One of: `"simple"` or `"anchored"`. #' @param w A {double} between {0} and {1}. The shrinkage level #' increases from 0 to 1. #' @param anchor A{double} vector with the anchor (benchmark) in which #' the allocation should not deviate too much from. Only used when `method = "anchored"`. #' @param normalize A{boolean} indicating whether the allocation should be #' normalized to sum {1} (full-investment constraint). The default is `normalize = TRUE`. #' @param endogenous A {boolean} indicating whether the risk-aversion parameter #' should be considered endogenous (only used when `method = "anchored"`). #' The default is `endogenous = TRUE`. ''' def epo(x, signal, lambda_, method="simple", w=None, anchor=None, normalize=True, endogenous=True): assert isinstance(method, str), "`method` must be a string." assert isinstance(lambda_, (int, float)), "`lambda` must be a number." assert isinstance(w, (int, float)), "`w` must be a number." assert isinstance(normalize, bool), "`normalize` must be a boolean." if method == "anchored" and anchor is None: raise ValueError("When the `anchored` method is chosen the `anchor` can't be `None`.") n = x.shape[1] vcov = x.cov() corr = x.corr() I = np.eye(n) V = np.zeros((n, n)) np.fill_diagonal(V, vcov.values.diagonal()) std = np.sqrt(V) s = signal a = anchor shrunk_cor = ((1 - w) * I @ corr.values) + (w * I) # equation 7 cov_tilde = std @ shrunk_cor @ std # topic 2.II: page 11 inv_shrunk_cov = solve(cov_tilde, np.eye(n)) if method == "simple": epo = (1 / lambda_) * inv_shrunk_cov @ signal # equation 16 elif method == "anchored": if endogenous: gamma = np.sqrt(a.T @ cov_tilde @ a) / np.sqrt(s.T @ inv_shrunk_cov @ cov_tilde @ inv_shrunk_cov @ s) epo = inv_shrunk_cov @ (((1 - w) * gamma * s) + ((w * I @ V @ a))) else: epo = inv_shrunk_cov @ (((1 - w) * (1 / lambda_) * s) + ((w * I @ V @ a))) else: raise ValueError("`method` not accepted. Try `simple` or `anchored` instead.") if normalize: epo = [0 if a < 0 else a for a in epo] epo = epo / np.sum(epo) return epo # 定义获取数据并调用优化函数的函数 def run_optimization(stocks, end_date): prices = get_price(stocks, count=1200, end_date=end_date, frequency='daily', fields=['close'])['close'] returns = prices.pct_change().dropna() # 计算收益率 d = np.diag(returns.cov()) a = (1/d) / (1/d).sum() # a= np.array([0.25,0.25,0.25,0.25]) weights = epo(x = returns, signal = returns.mean(), lambda_ = 10, method = "anchored", w = 1, anchor=a) return weights # 交易 def trade(context): end_date = context.previous_date weights = run_optimization(g.etf_pool, end_date) print("weights",weights) if weights is None: return total_value = context.portfolio.total_value # 获取总资产 index = 0 for w in weights: value = total_value * w # 确定每个标的的权重 order_target_value(g.etf_pool[index], value) # 调整标的至目标权重 index+=1 ```
文章分类
关于作者
水滴
注册时间: