Commit f502aea2 authored by wenwen.tang's avatar wenwen.tang 😕

加入risk_parity

parent 5bd442b0
......@@ -51,6 +51,7 @@ class SolveType(Enum):
INFEASIBLE = 0
MPT = 1
POEM = 2
RISK_PARITY = 3
@unique
......@@ -365,6 +366,15 @@ class Solver(ABC):
'''
pass
@abstractmethod
def solve_risk_parity(self):
'''
risk_parity计算
:return: 投组
'''
pass
@abstractmethod
def reset_navs(self, day):
'''
......
......@@ -40,7 +40,7 @@ py-jftech:
backtest: robo_executor.BacktestExecutor
datum: basic.datum.DefaultDatum
hold-report: portfolios.holder.DivHoldReportor
mpt: portfolios.builder.PoemARCPortfoliosBuilder
mpt: portfolios.builder.RiskParityARCPortfoliosBuilder
dividend-holder: portfolios.holder.InvTrustPortfoliosHolder
navs-sync: basic.sync.FundNavSync
email:
......@@ -115,7 +115,7 @@ portfolios: # 投组模块
checker: #投组检测模块
switch: on #是否开启检查
custom-type-priority: [3,2,1,4] # 检测优先级
month-fund-filter: {2:['TEMSCFA LX Equity'],12:['TEMHYAD LX Equity','TEMFIAI LX Equity']} # 根据月份删除某几档基金
month-fund-filter: {} # 根据月份删除某几档基金
reports: # 报告模块相关
navs:
type: FUND
......@@ -243,7 +243,7 @@ robo-executor: # 执行器相关
start-date: 2023-01-02 # 回测起始日期
end-date: 2023-10-31 # 回测截止日期
sealing-period: 10 #调仓封闭期
start-step: ${BACKTEST_START_STEP:1} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
start-step: ${BACKTEST_START_STEP:2} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
end-step: ${BACKTEST_END_STEP:3} # 回测从哪一步执行完成后结束执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
clean-up: on
real: # 实盘执行器
......
......@@ -121,7 +121,7 @@ class MptARCPortfoliosBuilder(MptPortfoliosBuilder):
try:
portfolio = rmp.get_one(day, type, risk)
if not portfolio:
result, detail = self.build_portfolio(day, type)
result = self.build_portfolio(day, type)
for build_risk, datas in result.items():
datas['portfolio'] = self._checker.check(day, json.loads(datas['portfolio']))
try:
......@@ -141,7 +141,9 @@ class MptARCPortfoliosBuilder(MptPortfoliosBuilder):
return {int(x[0]): x[1] for x in result.items()}
return None
except Exception as e:
logger.exception(f"build protfolio of type[{type.name}] and risk[{risk.name}] with date[{format_date(day)}] failure.", exc_info=e)
logger.exception(
f"build protfolio of type[{type.name}] and risk[{risk.name}] with date[{format_date(day)}] failure.",
exc_info=e)
raise e
def build_portfolio(self, day, type: PortfoliosType):
......@@ -180,6 +182,7 @@ class MptARCPortfoliosBuilder(MptPortfoliosBuilder):
@component(bean_name='mpt')
class PoemARCPortfoliosBuilder(MptARCPortfoliosBuilder):
def build_portfolio(self, day, type: PortfoliosType):
result, detail = super(PoemARCPortfoliosBuilder, self).build_portfolio(day, type)
risk = PortfoliosRisk.FT3
......@@ -200,3 +203,24 @@ class PoemARCPortfoliosBuilder(MptARCPortfoliosBuilder):
}
detail[risk]['mpt_cvar'] = mpt_cvar
return result, detail
@component(bean_name='mpt')
class RiskParityARCPortfoliosBuilder(MptPortfoliosBuilder):
def build_portfolio(self, day, type: PortfoliosType):
result = {}
risk = PortfoliosRisk.FT3
logger.info(
f"start to build protfolio of type[{type.name}] and risk[{risk.name}] with date[{format_date(day)}]")
solver = self._factory.create_solver(risk, type)
solver.reset_navs(day)
portfolio = solver.solve_risk_parity()
result[risk] = {
'solve': SolveType.RISK_PARITY,
'portfolio': json.dumps(portfolio),
} if portfolio else {
'solve': SolveType.INFEASIBLE
}
return result
......@@ -81,6 +81,10 @@ class DefaultSolver(Solver):
rtn = (self.navs / self.navs.shift(1) - 1)[1:]
return rtn.cov() * 252
@property
def risk_parity_sigma(self):
return self.navs.cov()
@property
def rtn_history(self):
result = self.rtn_matrix * 12
......@@ -188,6 +192,14 @@ class DefaultSolver(Solver):
self.debug_solve_result(model)
return self.calc_port_weight(model), self.calc_port_cvar(model)
def solve_risk_parity(self):
model = self.create_model()
model.objective = Objective(expr=sum(
[(model.z[i] * model.w[i] * (self.risk_parity_sigma.iloc[i] @ model.w) - model.z[j] * model.w[j] * (self.risk_parity_sigma.iloc[j] @ model.w)) ** 2
for i in model.indices for j in model.indices]), sense=minimize)
self._solver.solve(model)
return self.calc_port_weight(model)
def calc_port_weight(self, model):
id_list = self.navs.columns
weight_list = []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment