Commit 495d15b0 authored by 纪超's avatar 纪超

完成日志、配置文件、数据库工具模块

parent db33dba7
from framework import parse_date, get_quarter_start, get_config
from abc import ABC, abstractmethod
from enum import Enum, unique
from dateutil.relativedelta import relativedelta
@unique
......@@ -158,9 +156,20 @@ class PortfoliosBuilder(ABC):
@abstractmethod
def get_portfolios(self, day, risk: PortfoliosRisk, type: PortfoliosType = PortfoliosType.NORMAL):
'''
获取指定日期,指定风险等级的投资组合
获取指定日期,指定风险等级,指定类型的投资组合
:param type: 投组的类型
:param day: 指定日期
:param risk: 风险等级
:return: 资产组合字典{id: weight}
'''
pass
@abstractmethod
def build_portfolio(self, day, type: PortfoliosType):
'''
构建指定日期,指定类型的投资组合
:param day: 指定日期
:param type: 指定类型
:return 投资组合数据{risk: {...}},计算明细数据 {...}
'''
pass
import json
import pandas as pd
from abc import ABC, abstractmethod
from datetime import datetime as dt
import pandas as pd
from dateutil.relativedelta import relativedelta
from empyrical import sortino_ratio
from framework import filter_weekend, dict_remove, get_config, component, autowired, get_quarter_start
from api import AssetOptimize, Navs, BusinessException, Datum, AssetPoolType
from asset_pool.dao import robo_assets_pool as rop
from datetime import datetime as dt
from framework import filter_weekend, dict_remove, get_config, component, autowired, get_quarter_start
class SortinoAssetOptimize(AssetOptimize, ABC):
......@@ -88,7 +90,8 @@ class FundSortinoAssetOptimize(SortinoAssetOptimize):
def get_pct_change(self, fund_ids, day):
if not self._config:
raise BusinessException(f"find optimize, but not found sortino config.")
start = filter_weekend(sorted([day - relativedelta(days=1, **dict_remove(x, ('weight', 'name'))) for x in self._config])[0])
start = filter_weekend(
sorted([day - relativedelta(days=1, **dict_remove(x, ('weight', 'name'))) for x in self._config])[0])
fund_navs = pd.DataFrame(self._navs.get_fund_navs(fund_ids=tuple(fund_ids), min_date=start, max_date=day))
fund_navs.sort_values('nav_date', inplace=True)
fund_navs = fund_navs.pivot_table(index='nav_date', columns='fund_id', values='nav_cal')
......
from framework import component, autowired
from api import AssetPool, AssetOptimize, AssetRisk
from datetime import datetime as dt
from api import AssetPool, AssetOptimize, AssetRisk
from framework import component, autowired
@component
class FundAssetPool(AssetPool):
......@@ -14,4 +15,4 @@ class FundAssetPool(AssetPool):
def get_pool(self, day=dt.today()):
opti_pool = self._optimize.get_optimize_pool(day)
risk_pool = self._risk.get_risk_pool(day)
return [x for x in opti_pool if x not in risk_pool]
\ No newline at end of file
return [x for x in opti_pool if x not in risk_pool]
import json
import logging
from datetime import datetime as dt
import pandas as pd
......@@ -7,7 +8,9 @@ from scipy.stats import norm
from api import AssetRisk, Navs, AssetRiskDateType as DateType, Datum, AssetPoolType
from asset_pool.dao import asset_risk_dates as ard, asset_ewma_value as aev, robo_assets_pool as rap
from framework import component, autowired, get_config, log, format_date, block_execute
from framework import component, autowired, get_config, format_date, block_execute
logger = logging.getLogger(__name__)
def get_risk_start_date():
......@@ -38,7 +41,6 @@ class CvarEwmaAssetRisk(AssetRisk):
return json.loads(asset_pool['asset_ids'])
def is_risk(self, id, day) -> bool:
print(id, day)
asset_pool = rap.get_one(day, AssetPoolType.RISK)
if asset_pool:
return id in json.loads(asset_pool['asset_ids'])
......@@ -49,11 +51,11 @@ class CvarEwmaAssetRisk(AssetRisk):
def build_risk_date(self, asset_id, day=dt.today()):
risk_date = not None
try:
log.debug(f"start build risk date for asset[{asset_id}] to date[{format_date(day)}]")
logger.info(f"start build risk date for asset[{asset_id}] to date[{format_date(day)}]")
while risk_date is not None:
risk_date = self.get_next_date(asset_id, day=day)
except Exception as e:
log.exception(f"build risk date for asset[{asset_id}] after date[{risk_date}] error", e)
logger.exception(f"build risk date for asset[{asset_id}] after date[{risk_date}] error", e)
def get_next_date(self, asset_id, day=dt.today()):
last = ard.get_last_one(asset_id, day)
......@@ -83,7 +85,8 @@ class CvarEwmaAssetRisk(AssetRisk):
if row['rtn'] < rtns[rtns.date == cvar_start_date].iloc[0].rtn:
# 当日回报率跌破最低点, 则直接触发
tigger = True
elif row['rtn'] <= self._config['cvar']['threshold'] and len(cvar_rtns) >= self._config['cvar']['min-volume']:
elif row['rtn'] <= self._config['cvar']['threshold'] and len(cvar_rtns) >= self._config['cvar'][
'min-volume']:
# 当日回报率小于等于阀值并且有足够cvar累计计算数据,则计算cvar判断
alpha = 1 - self._config['cvar']['coef']
mean = cvar_rtns['rtn'].mean()
......
from framework import read, write, where, format_date
__COLUMNS__ = {
'aev_id': 'id',
'aev_date': 'date',
......@@ -30,7 +29,7 @@ def get_last_one(asset_id, max_date=None):
@read
def get_list(asset_id, min_date=None, max_date=None):
sqls =[]
sqls = []
if min_date:
sqls.append(f"aev_date >= '{format_date(min_date)}'")
if max_date:
......
from framework import read, write, where, format_date
from api import AssetRiskDateType as DateType
from framework import read, write, where, format_date
__COLUMNS__ = {
'ard_id': 'id',
......@@ -28,4 +28,3 @@ def get_last_one(fund_id, date, type: DateType = None):
select {','.join([f"`{x[0]}` as `{x[1]}`" for x in __COLUMNS__.items()])}
from asset_risk_dates {where(sql, **kwargs)} order by ard_date desc, ard_type asc limit 1
'''
import json
from framework import read, write, where, format_date
from api import AssetPoolType
from framework import read, write, where, format_date
__COLUMNS__ = {
'rap_id': 'id',
......
from framework import read, where, format_date, to_tuple
__COLUMNS__ = {
'rfn_fund_id': 'fund_id',
'rfn_date': 'nav_date',
......
import json
from api import DatumType, Datum
from basic.dao import robo_base_datum as rbd
from framework import component, parse_date
......
import pandas as pd
from api import Navs, Datum
from basic.dao import robo_exrate as re, robo_fund_navs as rfn
from framework import get_config, component, autowired
......@@ -18,7 +19,8 @@ class DefaultNavs(Navs):
navs = pd.DataFrame(navs)
navs = navs.pivot_table(index='nav_date', columns='fund_id', values='nav_cal')
for exrate_config in self._config['exrate']:
exrate = pd.DataFrame(re.get_exrates(ticker=exrate_config['ticker'], min_date=navs.index.min(), max_date=navs.index.max()))
exrate = pd.DataFrame(re.get_exrates(ticker=exrate_config['ticker'], min_date=navs.index.min(),
max_date=navs.index.max()))
exrate = exrate[['date', 'close']]
exrate.set_index('date', inplace=True)
for fund in self._datum.get_fund_datums(crncy=exrate_config['from']):
......@@ -30,7 +32,3 @@ class DefaultNavs(Navs):
navs.sort_values(by=['fund_id', 'nav_date'], inplace=True)
navs = navs.to_dict('records')
return navs
if __name__ == '__main__':
print(isinstance((), tuple))
......@@ -16,10 +16,10 @@ framework:
user: jft-ra@thizgroup.com
password: 5dbb#30ec6d3
mulit-process:
max-workers: 4
max-workers: 8
logger:
version: 1
use: ${LOG_NAME:root}
use: prod
formatters:
brief:
format: "%(asctime)s - %(levelname)s - %(message)s"
......@@ -29,7 +29,7 @@ framework:
console:
class: logging.StreamHandler
formatter: simple
level: INFO
level: DEBUG
stream: ext://sys.stdout
file:
class: logging.handlers.TimedRotatingFileHandler
......@@ -42,9 +42,11 @@ framework:
when: D
loggers:
prod:
handlers: [ console,file ]
handlers: [ console, file ]
level: INFO
propagate: 0
propagate: no
portfolios:
level: DEBUG
root:
level: INFO
handlers: [ console ]
......
......@@ -2,9 +2,9 @@ from .date_utils import *
from .base import *
from .database import read, write, transaction, where, to_columns
from .env_config import config, get_config
from .logger import build_logger, logger as log
from .logs import build_logger, get_logger
from .injectable import component, autowired, get_instance, init_injectable as _init_injectable
from .mulit_process import process_pool, create_process_pool, block_execute
_init_injectable()
del injectable, logger, env_config, database, base, date_utils, _init_injectable, mulit_process
del injectable, logs, env_config, database, base, date_utils, _init_injectable, mulit_process
......@@ -4,7 +4,7 @@ from functools import partial
import yaml
from .base import *
from framework.base import *
has_regex_module = False
ENV_VAR_MATCHER = re.compile(
......@@ -17,7 +17,6 @@ ENV_VAR_MATCHER = re.compile(
""", re.VERBOSE
)
IMPLICIT_ENV_VAR_MATCHER = re.compile(
r"""
.* # matches any number of any characters
......@@ -27,7 +26,6 @@ IMPLICIT_ENV_VAR_MATCHER = re.compile(
""", re.VERBOSE
)
RECURSIVE_ENV_VAR_MATCHER = re.compile(
r"""
\$\{ # match characters `${` literally
......@@ -89,7 +87,9 @@ yaml.add_implicit_resolver(
config = build_config()
def get_config(module: str = None):
def get_config(module: str = None, file: str = None):
if module == '__main__':
module = file
result = config
if module:
for name in [x.replace('_', '-') for x in module.split('.')]:
......
import logging
import os
from logging import config as cf, getLogger
from framework.env_config import get_config
from logging import config as cf
from framework.base import get_project_path
from framework.env_config import get_config
def build_logger(config, name='root'):
def build_logger(config):
if 'handlers' in config and 'file' in config['handlers']:
file = config['handlers']['file']
path = os.path.join(get_project_path(), file["filename"])
os.makedirs(os.path.split(path)[0], exist_ok=True)
file["filename"] = os.path.abspath(path)
cf.dictConfig(config)
return getLogger(name)
config = get_config(__name__)
logger = build_logger(config, name=config['use'] if 'use' in config else None) if config else None
config = get_config("framework.logger")
if config:
build_logger(config)
def get_logger(name=None):
return logging.getLogger(config['use'] if 'use' in config and config['use'] is not None else name)
from concurrent.futures import ProcessPoolExecutor, as_completed
from framework.env_config import get_config
from functools import partial, wraps
config = get_config(__name__)
process_pool = ProcessPoolExecutor(max_workers=config['max-workers'] or 2)
......
from framework import autowired, parse_date, log
from framework import autowired, parse_date, get_logger
from api import PortfoliosBuilder, PortfoliosRisk
logger = get_logger('main')
@autowired
@autowired(names={'builder': 'poem'})
def start(builder: PortfoliosBuilder = None):
day = parse_date('2022-11-07')
log.info(builder.get_portfolios(day, PortfoliosRisk.FT3))
def test(arg):
if arg:
return 1, 1
else:
return None
logger.info(builder.get_portfolios(day, PortfoliosRisk.FT3))
if __name__ == '__main__':
log.info("start")
start()
\ No newline at end of file
logger.info("info")
logger.debug('debug')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
# start()
import json
import os
import sys
import json
import pandas as pd
from dateutil.relativedelta import relativedelta
......@@ -8,9 +8,11 @@ from numpy import NAN
from pyomo.environ import *
from api import PortfoliosBuilder, PortfoliosRisk, AssetPool, Navs, PortfoliosType, Datum, SolveType
from framework import component, autowired, get_config
from framework import component, autowired, get_config, format_date, get_logger
from portfolios.dao import robo_mpt_portfolios as rmp
logger = get_logger(__name__)
def create_solver():
if sys.platform.find('win') == 0:
......@@ -24,7 +26,8 @@ def create_solver():
class MptSolver:
@autowired
def __init__(self, risk: PortfoliosRisk, type: PortfoliosType, assets: AssetPool = None, navs: Navs = None, datum: Datum = None):
def __init__(self, risk: PortfoliosRisk, type: PortfoliosType, assets: AssetPool = None, navs: Navs = None,
datum: Datum = None):
self.__navs = None
self.risk = risk
self.type = type or PortfoliosType.NORMAL
......@@ -59,17 +62,32 @@ class MptSolver:
result = self.rtn_matrix * 12
return result.values
@property
def beta(self):
return self.get_config('mpt.cvar-beta')
@property
def k_beta(self):
return round(len(self.rtn_history) * self.get_config('mpt.cvar-beta') + 0.499999)
return round(len(self.rtn_history) * self.beta + 0.499999)
@property
def pct_value(self):
return self.get_config('mpt.quantile')
def solve_max_rtn(self):
model = self.create_model()
model.objective = Objective(expr=sum([model.w[i] * self.rtn_annualized[i] for i in model.indices]), sense=maximize)
model.objective = Objective(expr=sum([model.w[i] * self.rtn_annualized[i] for i in model.indices]),
sense=maximize)
self._solver.solve(model)
self.debug_solve_result(model)
max_rtn = self.calc_port_rtn(model)
max_var = self.calc_port_var(model)
minCVaR_whenMaxR = self.calc_port_cvar(model)
logger.debug({
'max_rtn': max_rtn,
'max_var': max_var,
'minCVaR_whenMaxR': minCVaR_whenMaxR,
})
return max_rtn, max_var, minCVaR_whenMaxR
def solve_min_rtn(self):
......@@ -78,13 +96,21 @@ class MptSolver:
expr=sum([model.w[i] * model.w[j] * self.sigma.iloc[i, j] for i in model.indices for j in model.indices]),
sense=minimize)
self._solver.solve(model)
self.debug_solve_result(model)
min_rtn = self.calc_port_rtn(model)
min_var = self.calc_port_var(model)
maxCVaR_whenMinV = self.calc_port_cvar(model)
logger.debug({
'min_rtn': min_rtn,
'min_var': min_var,
'maxCVaR_whenMinV': maxCVaR_whenMinV,
})
return min_rtn, min_var, maxCVaR_whenMinV
def solve_mpt(self, min_rtn, max_rtn):
big_y = min_rtn + self.get_config('mpt.quantile') * (max_rtn - min_rtn)
logger.debug(f'...... ...... ...... ...... ...... ...... ...... ...... MPT ... sub risk : pct_value = {self.pct_value}')
big_y = min_rtn + self.pct_value * (max_rtn - min_rtn)
logger.debug(f'big_Y = target_Return = {big_y}')
model = self.create_model()
model.cons_rtn = Constraint(expr=sum([model.w[i] * self.rtn_annualized[i] for i in model.indices]) >= big_y)
model.objective = Objective(
......@@ -92,28 +118,37 @@ class MptSolver:
sense=minimize)
result = self._solver.solve(model)
if result.solver.termination_condition == TerminationCondition.infeasible:
logger.debug('...... MPT: Infeasible Optimization Problem.')
return None, None
logger.debug('...... MPT: Has solution.')
self.debug_solve_result(model)
return self.calc_port_weight(model), self.calc_port_cvar(model)
def solve_poem(self, min_rtn, max_rtn, base_cvar, max_cvar):
k_history = len(self.rtn_history)
quantile = self.get_config('mpt.quantile')
quantile = self.pct_value
logger.debug(f'...... ...... ...... ...... ...... ...... ...... ...... POEM With CVaR constraints ... sub risk : pct_value = {quantile}')
big_y = min_rtn + quantile * (max_rtn - min_rtn)
small_y = base_cvar + (max_cvar - base_cvar) * self.get_config('poem.cvar-scale-factor') * quantile
logger.debug(f'big_Y = target_Return = {big_y} | small_y = target_cvar = {small_y}')
model = self.create_model()
model.alpha = Var(domain=Reals)
model.x = Var(range(k_history), domain=NonNegativeReals)
model.cons_cvar_aux = Constraint(range(k_history), rule=lambda m, k: m.x[k] >= m.alpha - sum([m.w[i] * self.rtn_history[k][i] for i in m.indices]))
model.cons_cvar_aux = Constraint(range(k_history), rule=lambda m, k: m.x[k] >= m.alpha - sum(
[m.w[i] * self.rtn_history[k][i] for i in m.indices]))
model.cons_rtn = Constraint(expr=sum([model.w[i] * self.rtn_annualized[i] for i in model.indices]) >= big_y)
model.cons_cvar = Constraint(expr=model.alpha - (1 / self.k_beta) * sum([model.x[k] for k in range(k_history)]) >= small_y)
model.cons_cvar = Constraint(
expr=model.alpha - (1 / self.k_beta) * sum([model.x[k] for k in range(k_history)]) >= small_y)
result = self._solver.solve(model)
if result.solver.termination_condition == TerminationCondition.infeasible:
logger.debug('...... POEM: Infeasible Optimization Problem.')
return None, None
logger.debug('...... POEM: Has solution.')
self.debug_solve_result(model)
return self.calc_port_weight(model), self.calc_port_cvar(model)
def calc_port_weight(self, model):
id_list = self._navs.columns
id_list = self.navs.columns
weight_list = []
for i in model.indices:
weight_list.append(model.w[i]._value * model.z[i]._value)
......@@ -140,12 +175,14 @@ class MptSolver:
return sum([model.w[i]._value * self.rtn_annualized[i] for i in model.indices])
def calc_port_var(self, model):
return sum([model.w[i]._value * model.w[j]._value * self.sigma.iloc[i, j] for i in model.indices for j in model.indices])
return sum([model.w[i]._value * model.w[j]._value * self.sigma.iloc[i, j] for i in model.indices for j in
model.indices])
def calc_port_cvar(self, model):
port_r_hist = []
for k in range(len(self.rtn_history)):
port_r_hist.append(sum([model.w[i]._value * model.z[i]._value * self.rtn_history[k][i] for i in model.indices]))
port_r_hist.append(
sum([model.w[i]._value * model.z[i]._value * self.rtn_history[k][i] for i in model.indices]))
port_r_hist.sort()
return sum(port_r_hist[0: self.k_beta]) / self.k_beta
......@@ -161,11 +198,12 @@ class MptSolver:
model = ConcreteModel()
model.indices = range(0, len(self._navs.columns))
model.indices = range(0, len(self.navs.columns))
model.w = Var(model.indices, domain=NonNegativeReals)
model.z = Var(model.indices, domain=Binary)
model.cons_sum_weight = Constraint(expr=sum([model.w[i] for i in model.indices]) == 1)
model.cons_num_asset = Constraint(expr=inequality(min_count, sum([model.z[i] for i in model.indices]), max_count, strict=False))
model.cons_num_asset = Constraint(
expr=inequality(min_count, sum([model.z[i] for i in model.indices]), max_count, strict=False))
model.cons_bounds_low = Constraint(model.indices, rule=lambda m, i: m.z[i] * low_weight <= m.w[i])
model.cons_bounds_up = Constraint(model.indices, rule=lambda m, i: m.z[i] * high_weight >= m.w[i])
return model
......@@ -184,9 +222,11 @@ class MptSolver:
navs = navs.sort_index()
navs_nan = navs.isna().sum()
navs.drop(columns=[x for x in navs_nan.index if navs_nan.loc[x] >= self.get_config('navs.max-nan.asset')], inplace=True)
navs.drop(columns=[x for x in navs_nan.index if navs_nan.loc[x] >= self.get_config('navs.max-nan.asset')],
inplace=True)
navs_nan = navs.apply(lambda r: r.isna().sum() / len(r), axis=1)
navs.drop(index=[x for x in navs_nan.index if navs_nan.loc[x] >= self.get_config('navs.max-nan.day')], inplace=True)
navs.drop(index=[x for x in navs_nan.index if navs_nan.loc[x] >= self.get_config('navs.max-nan.day')],
inplace=True)
navs.fillna(method='ffill', inplace=True)
self.__navs = navs
......@@ -198,11 +238,31 @@ class MptSolver:
else:
return None
return config
value = load_config(self._config[self.type.value] if self.type is not PortfoliosType.NORMAL else self._config)
if value is None:
value = load_config(self._config)
return value[f'ft{self.risk.value}'] if value and isinstance(value, dict) else value
def debug_solve_result(self, model):
if logger.isEnabledFor(DEBUG):
logger.debug('===============================')
logger.debug('solution: id | w(id)')
w_sum = 0
for i in model.indices:
if model.z[i]._value == 1:
logger.debug(f'{self.navs.columns[i]} | {model.w[i]._value}')
w_sum += model.w[i]._value
logger.debug(f'w_sum = {w_sum}')
logger.debug({
'beta': self.beta,
'kbeta': self.k_beta,
'port_R': self.calc_port_rtn(model),
'port_V': self.calc_port_cvar(model),
'port_CVaR': self.calc_port_cvar(model)
})
logger.debug('-------------------------------')
@component(bean_name='mpt')
class MptPortfoliosBuilder(PortfoliosBuilder):
......@@ -216,67 +276,71 @@ class MptPortfoliosBuilder(PortfoliosBuilder):
def get_portfolios(self, day, risk: PortfoliosRisk, type: PortfoliosType = PortfoliosType.NORMAL):
portfolio = rmp.get_one(day, type, risk)
if not portfolio:
self.build_portfolio(day, type)
result, detail = self.build_portfolio(day, type)
for build_risk, datas in result.items():
rmp.insert({
**{datas},
'risk': build_risk,
'type': type,
'date': day
})
portfolio = rmp.get_one(day, type, risk)
return json.loads(portfolio['portfolio']) if SolveType(portfolio['rmp_rolve']) is not SolveType.INFEASIBLE else None
return json.loads(portfolio['portfolio']) if SolveType(portfolio['solve']) is not SolveType.INFEASIBLE else None
def build_portfolio(self, day, type: PortfoliosType):
result = {}
detail = {}
for risk in PortfoliosRisk:
logger.info(
f"start build protfolio of type[{type.name}] and risk[{risk.name}] with date[{format_date(day)}]")
solver = MptSolver(risk, type)
solver.reset_navs(day)
logger.debug({
'Khist': len(solver.rtn_history),
'beta': solver.get_config('mpt.cvar-beta'),
'Kbeta': solver.k_beta,
})
max_rtn, max_var, minCVaR_whenMaxR = solver.solve_max_rtn()
min_rtn, min_var, maxCVaR_whenMinV = solver.solve_min_rtn()
portfolio, cvar = solver.solve_mpt(min_rtn, max_rtn)
if portfolio:
rmp.insert({
'date': day,
'risk': risk,
'type': type,
'solve': SolveType.MPT,
'portfolio': json.dumps(portfolio),
'cvar': cvar
})
else:
rmp.insert({
'date': day,
'risk': risk,
'type': type,
'solve': SolveType.INFEASIBLE
})
result[risk] = {
'solve': SolveType.MPT,
'portfolio': json.dumps(portfolio),
'cvar': cvar
} if portfolio else {
'solve': SolveType.INFEASIBLE
}
detail[risk] = {
'max_rtn': max_rtn,
'max_var': max_var,
'minCVaR_whenMaxR': minCVaR_whenMaxR,
'min_rtn': min_rtn,
'min_var': min_var,
'maxCVaR_whenMinV': maxCVaR_whenMinV,
}
return result, detail
@component(bean_name='poem')
class PoemPortfoliosBuilder(MptPortfoliosBuilder):
def build_portfolio(self, day, type: PortfoliosType):
result, detail = super(PoemPortfoliosBuilder, self).build_portfolio(day, type)
for risk in PortfoliosRisk:
if result[risk]['solve'] is SolveType.INFEASIBLE:
continue
solver = MptSolver(risk, type)
solver.reset_navs(day)
max_rtn, max_var, minCVaR_whenMaxR = solver.solve_max_rtn()
min_rtn, min_var, maxCVaR_whenMinV = solver.solve_min_rtn()
portfolio, cvar = solver.solve_mpt(min_rtn, max_rtn)
solve = SolveType.MPT
if portfolio is not None:
poem_port, poem_cvar = solver.solve_poem(min_rtn, max_rtn, cvar, maxCVaR_whenMinV)
if poem_port:
portfolio = poem_port
cvar = poem_cvar
solve = SolveType.POEM
min_rtn = detail[risk]['min_rtn']
max_rtn = detail[risk]['max_rtn']
mpt_cvar = result[risk]['cvar']
maxCVaR_whenMinV = detail[risk]['maxCVaR_whenMinV']
portfolio, cvar = solver.solve_poem(min_rtn, max_rtn, mpt_cvar, maxCVaR_whenMinV)
if portfolio:
rmp.insert({
'date': day,
'risk': risk,
'type': type,
'solve': solve,
result[risk] = {
'solve': SolveType.POEM,
'portfolio': json.dumps(portfolio),
'cvar': cvar
})
else:
rmp.insert({
'date': day,
'risk': risk,
'type': type,
'solve': SolveType.INFEASIBLE
})
}
detail[risk]['mpt_cvar'] = mpt_cvar
return result, detail
from datetime import datetime
from framework import read, write, where, format_date
from enum import Enum
from api import PortfoliosRisk, PortfoliosType
from framework import read, write, where, format_date
__COLUMNS__ = {
'rmp_id': 'id',
......@@ -31,6 +32,6 @@ def insert(datas):
@read(one=True)
def get_one(day, type: PortfoliosType, risk: PortfoliosRisk):
return f'''
select {','.join([x for x in __COLUMNS__.keys()])} from robo_mpt_portfolios
select {','.join([f"{x[0]} as {x[1]}" for x in __COLUMNS__.items()])} from robo_mpt_portfolios
{where(rmp_date=day, rmp_risk=risk, rmp_type=type)}
'''
from api import PortfoliosBuilder, PortfoliosType
from framework import autowired, parse_date, get_logger
logger = get_logger('test')
@autowired(names={'builder': 'poem'})
def test_portfolio_builder(builder: PortfoliosBuilder = None):
result, detail = builder.build_portfolio(parse_date('2011-11-07'), PortfoliosType.NORMAL)
logger.info(result)
logger.info(detail)
if __name__ == '__main__':
test_portfolio_builder()
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