Commit d82a0934 authored by pengxiong@wealthgrow.cn's avatar pengxiong@wealthgrow.cn

Merge remote-tracking branch 'origin/dev' into dev

parents 7801abf3 f9396627
......@@ -14,8 +14,7 @@ import os
import sys
import yaml
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import sessionmaker, scoped_session
env = sys.argv[-1]
work_dir = os.getcwd()
......@@ -58,9 +57,9 @@ tamp_user_engine = create_engine(
),
echo=True
)
tamp_product_session = sessionmaker(bind=tamp_product_engine, autocommit=True)()
tamp_order_session = sessionmaker(bind=tamp_order_engine, autocommit=True)()
tamp_user_session = sessionmaker(bind=tamp_user_engine, autocommit=True)()
tamp_product_session = scoped_session(sessionmaker(bind=tamp_product_engine))()
tamp_order_session = scoped_session(sessionmaker(bind=tamp_order_engine))()
tamp_user_session = scoped_session(sessionmaker(bind=tamp_user_engine))()
# redis = redis.StrictRedis(
# host=config[env]['redis']['host'],
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -22,7 +22,7 @@ class UserCustomerDataAdaptor:
month_date = ""
end_date = ""
group_data = {}
trade_cal = None
trade_cal_date = None
all_fund_distribution = {}
all_fund_performance = {}
......@@ -32,13 +32,15 @@ class UserCustomerDataAdaptor:
self.compare_index_id = index_id
p_end_date = pd.to_datetime(end_date).date()
p_end_date = datetime.date(year=p_end_date.year, month=p_end_date.month, day=1) - datetime.timedelta(days=1)
# self.end_date = pd.to_datetime(str(p_end_date))
self.end_date = pd.to_datetime("2020-11-23")
self.end_date = pd.to_datetime(str(p_end_date))
# self.end_date = pd.to_datetime("2020-11-23")
p_start_date = datetime.date(year=p_end_date.year, month=p_end_date.month, day=1)
self.month_start_date = pd.to_datetime("2020-11-16")
self.month_start_date = p_start_date
# self.month_start_date = pd.to_datetime("2020-11-16")
self.user_customer_order_df = self.get_user_customer_order_data()
self.fund_nav_total, self.fund_cnav_total = self.get_customer_fund_nav_data()
self.get_customer_index_nav_data()
self.index_df = self.get_customer_index_nav_data()
self.total_customer_order_cnav_df = self.total_combine_data()
self.group_operate()
@staticmethod
......@@ -82,7 +84,7 @@ class UserCustomerDataAdaptor:
def get_customer_fund_nav_data(self):
now_date = datetime.datetime.now().strftime("%Y%m%d")
trade_date_df = self.get_trade_cal("20000101", now_date)
self.trade_cal = trade_date_df
self.trade_cal_date = trade_date_df
all_fund_nav = pd.DataFrame(index=trade_date_df["datetime"])
all_fund_cnav = pd.DataFrame(index=trade_date_df["datetime"])
......@@ -94,21 +96,21 @@ class UserCustomerDataAdaptor:
cur_fund_nav_df = pd.DataFrame(list(data), columns=['price_date', 'nav', 'cnav'])
# # 对应基金分红
# sql = """select distinct `distribute_date`, `distribution` from `fund_distribution` where `fund_id`='{}' and `distribute_type`='1' order by `distribute_date` ASC""".format(
# cur_fund_id)
# cur = tamp_product_session.execute(sql)
# data = cur.fetchall()
# cur_fund_distribution_df = pd.DataFrame(list(data), columns=['price_date', 'distribution'])
# self.all_fund_distribution[cur_fund_id] = cur_fund_distribution_df
#
# # 对应基金performance数据
# sql = """select distinct `price_date`, `ret_cum_1w`, `ret__cum_1m`, `ret_cum_6m`, `ret_cum_1y`, `ret_cum_ytd`, `ret_cum_incep` from `fund_performance` where `fund_id`='{}' order by `price_date` ASC""".format(
# cur_fund_id)
# cur = tamp_product_session.execute(sql)
# data = cur.fetchall()
# cur_fund_performance_df = pd.DataFrame(list(data),
# columns=['price_date', 'ret_cum_1w', 'ret__cum_1m', 'ret_cum_6m', 'ret_cum_1y', 'ret_cum_ytd', 'ret_cum_incep'])
# self.all_fund_performance[cur_fund_id] = cur_fund_performance_df
sql = """select distinct `distribute_date`, `distribution` from `fund_distribution` where `fund_id`='{}' and `distribute_type`='1' order by `distribute_date` ASC""".format(
cur_fund_id)
cur = tamp_product_session.execute(sql)
data = cur.fetchall()
cur_fund_distribution_df = pd.DataFrame(list(data), columns=['price_date', 'distribution'])
self.all_fund_distribution[cur_fund_id] = cur_fund_distribution_df
# 对应基金performance数据
sql = """select distinct `price_date`, `ret_1w`, `ret_cum_1m`, `ret_cum_6m`, `ret_cum_1y`, `ret_cum_ytd`, `ret_cum_incep` from `fund_performance` where `fund_id`='{}' order by `price_date` ASC""".format(
cur_fund_id)
cur = tamp_product_session.execute(sql)
data = cur.fetchall()
cur_fund_performance_df = pd.DataFrame(list(data),
columns=['price_date', 'ret_1w', 'ret_cum_1m', 'ret_cum_6m', 'ret_cum_1y', 'ret_cum_ytd', 'ret_cum_incep'])
self.all_fund_performance[cur_fund_id] = cur_fund_performance_df
cur_fund_nav_df["price_date"] = pd.to_datetime(cur_fund_nav_df["price_date"])
cur_fund_nav_df.set_index("price_date", inplace=True)
......@@ -128,12 +130,12 @@ class UserCustomerDataAdaptor:
index_df["price_date"] = pd.to_datetime(index_df["price_date"])
index_df.set_index("price_date", inplace=True)
self.fund_cnav_total["index"] = index_df["index"]
self.index_df = index_df
return index_df
# 分组合计算
def group_operate(self):
for folio in self.user_customer_order_df["folio_name"].unique():
cur_folio_order_df = self.user_customer_order_df[self.user_customer_order_df["folio_name"] == folio]
fund_id_list = list(self.user_customer_order_df["fund_id"].unique())
......@@ -216,5 +218,64 @@ class UserCustomerDataAdaptor:
self.group_data[p_folio] = {"result_cnav_data": cnav_df, "order_df": p_order_df}
return cnav_df
# 所有的数据操作
def total_combine_data(self):
pass
p_order_df = self.user_customer_order_df.copy()
p_nav_df = self.fund_nav_total.copy()
p_cnav_df = self.fund_cnav_total.copy()
start_date = pd.to_datetime(p_order_df["confirm_share_date"].min())
cnav_df = p_cnav_df[p_cnav_df.index >= start_date].copy()
p_fund_id_list = list(p_order_df["fund_id"].unique())
for p_fund_id in p_fund_id_list:
order_min_date = p_order_df[p_order_df["fund_id"] == p_fund_id]["confirm_share_date"].min()
if pd.to_datetime(order_min_date) > start_date:
cnav_df.loc[:order_min_date - datetime.timedelta(days=1), p_fund_id] = np.nan
for index, row in p_order_df.iterrows():
cur_fund_id = str(row["fund_id"])
confirm_share_date = pd.to_datetime(row["confirm_share_date"])
# 根据确认净值日查看是否含有累积净值的数据,如果没有按照前后差值推算当天累积净值
if pd.isnull(cnav_df.loc[confirm_share_date, cur_fund_id]):
last_nav_data = p_nav_df[p_nav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1)
last_cnav_data = p_cnav_df[p_cnav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1)
# 判断上个净值日和当前确认日之中是否存在分红日
"""need add judge"""
if len(last_nav_data) < 1:
cnav_df.loc[confirm_share_date, cur_fund_id] = row["nav"]
else:
diff_nav = row["nav"] - last_nav_data.values[0]
cur_cnav = last_cnav_data.values[0] + diff_nav
cnav_df.loc[confirm_share_date, cur_fund_id] = cur_cnav
cnav_df = cnav_df.dropna(axis=0, how="all").fillna(method='ffill')
for index, row in p_order_df.iterrows():
cur_fund_id = str(row["fund_id"])
confirm_share_date = pd.to_datetime(row["confirm_share_date"])
if cur_fund_id + "_amount" not in cnav_df:
profit = cnav_df[cur_fund_id].dropna() - cnav_df[cur_fund_id].dropna().shift(1)
cnav_df[cur_fund_id + "_profit"] = profit
cnav_df[cur_fund_id + "_profit_ratio"] = profit / cnav_df[cur_fund_id].dropna().shift(1)
cnav_df[cur_fund_id + "_amount"] = 0
cnav_df[cur_fund_id + "_earn"] = 0
# cnav_df[cur_fund_id + "_cum_earn"] = 0
cnav_df[cur_fund_id + "_share"] = 0
# buy
if row['order_type'] == 1:
cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] += row["confirm_amount"]
cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] += row["confirm_share"]
# sell
elif row['order_type'] == 2:
cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] -= row["confirm_amount"]
cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] -= row["confirm_share"]
cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_profit"] * cnav_df[cur_fund_id + "_share"]
cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_earn"].apply(lambda x: float(x))
cnav_df[cur_fund_id + "_cum_earn"] = cnav_df[cur_fund_id + "_earn"].cumsum()
return cnav_df
......@@ -14,121 +14,282 @@ from app.service.data_service import UserCustomerDataAdaptor
from app.utils.week_evaluation import *
def resample(df, trading_cal, freq):
"""对基金净值表进行粒度不同的重采样,并剔除不在交易日中的结果
Args:
df ([DataFrame]): [原始基金净值表]
trading_cal ([type]): [上交所交易日表]
freq ([type]): [重采样频率: 1:工作日,2:周, 3:月, 4:半月, 5:季度]
Returns:
[DataFrame]: [重采样后剔除不在交易日历中的净值表和交易日历以净值日期为索引的合表]
"""
freq_dict = {1: 'B', 2: 'W-FRI', 3: 'M', 4: 'SM', 5: 'Q'}
resample_freq = freq_dict[freq]
# 按采样频率进行重采样并进行净值的前向填充
df = df.resample(rule=resample_freq).ffill()
# 根据采样频率确定最大日期偏移量(保证偏移后的日期与重采样的日期在同一周,同一月,同一季度等)
timeoffset_dict = {1: 1, 2: 5, 3: 30, 4: 15, 5: 120}
timeoffetmax = timeoffset_dict[freq]
# Dataframe不允许直接修改index,新建一份index的复制并转为list
new_index = list(df.index)
# 遍历重采样后的日期
for idx, date in enumerate(df.index):
# 如果重采样后的日期不在交易日历中
if date not in trading_cal.index:
# 对重采样后的日期进行偏移
for time_offset in range(1, timeoffetmax):
# 如果偏移后的日期在交易日历中,保留偏移后的日期
if date - datetime.timedelta(days=time_offset) in trading_cal.index:
new_index[idx] = date - datetime.timedelta(days=time_offset)
# 任意一天满足立即退出循环
break
# 更改净值表的日期索引为重采样后且在交易日内的日期
df.index = pd.Series(new_index)
return df
class UserCustomerResultAdaptor(UserCustomerDataAdaptor):
total_result_data = {}
group_result_data = []
group_result_data = {}
def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())):
# super().__init__()
super().__init__(user_id, customer_id, end_date)
# 综述数据
def get_total_data(self):
# 组合结果数据
def calculate_group_result_data(self):
for folio in self.group_data.keys():
# self.group_result_data.append({folio: {}})
folio_report_data = {}
cur_folio_result_cnav_data = self.group_data[folio]["result_cnav_data"]
cur_folio_order_data = self.group_data[folio]["order_df"]
freq_max = cur_folio_order_data["freq"].max()
first_trade_date = cur_folio_order_data["confirm_share_date"].min()
fund_id_list = list(cur_folio_order_data["fund_id"].unique())
fund_id_list_earn = [i + "_earn" for i in fund_id_list]
fund_id_list_amount = [i + "_amount" for i in fund_id_list]
# fund_id_list_amount = [i + "_amount" for i in fund_id_list]
profit_df = cur_folio_result_cnav_data[fund_id_list_earn]
resample_df = resample(cur_folio_result_cnav_data, self.trade_cal, 2)
# 组合收益率
return_ratio_serise = self.combination_yield(cur_folio_result_cnav_data, fund_id_list)
# 组合收益率数组
return_ratio_df = self.combination_yield(cur_folio_result_cnav_data, fund_id_list)
resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max)
# 总成本
total_cost = float(cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_amount"].sum() - \
cur_folio_order_data[cur_folio_order_data["order_type"] == 2]["confirm_amount"].sum())
folio_report_data["total_cost"] = total_cost
# 累积盈利
cumulative_profit = profit_df.sum().sum()
# 年化收益
return_ratio_year = 0
"""*************************年化收益*******************************"""
folio_report_data["cumulative_profit"] = float(cumulative_profit)
# 区间年化收益率
n_freq = freq_days(int(freq_max))
return_ratio_year = annual_return((resample_df["cum_return_ratio"].values[-1]-1), resample_df, n_freq)
folio_report_data["return_ratio_year"] = float(return_ratio_year)
# 波动率
volatility_ = volatility(resample_df["cum_return_ratio"], n_freq)
folio_report_data["volatility"] = float(volatility_)
# 最大回撤
drawdown = max_drawdown(resample_df["cum_return_ratio"])
folio_report_data["max_drawdown"] = drawdown
# 夏普比率
sim = simple_return(resample_df["cum_return_ratio"])
exc = excess_return(sim, BANK_RATE, n_freq)
sharpe = sharpe_ratio(exc, sim, n_freq)
folio_report_data["sharpe"] = float(sharpe)
# 期末资产
ending_assets = cumulative_profit + total_cost
folio_report_data["ending_assets"] = float(ending_assets)
# 本月收益
cur_month_profit_df = profit_df.loc[self.month_start_date:self.end_date+datetime.timedelta(days=1), fund_id_list_earn]
cur_month_profit = cur_month_profit_df.sum().sum()
folio_report_data["cur_month_profit"] = float(cur_month_profit)
# 本月累积收益率
cur_month_profit_ratio = return_ratio_serise.loc[self.month_start_date:].sum()
last_profit_ratio = return_ratio_df.loc[:self.month_start_date, "cum_return_ratio"].values
cur_profit_ratio = return_ratio_df.loc[self.month_start_date:, "cum_return_ratio"].values
if len(last_profit_ratio) <= 0:
cur_month_profit_ratio = cur_profit_ratio[-1] - 1
else:
cur_month_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1]
folio_report_data["cur_month_profit_ratio"] = float(cur_month_profit_ratio)
# 今年累积收益
cur_year_date = pd.to_datetime(str(datetime.date(year=self.end_date.year, month=1, day=1)))
cur_year_profit_df = profit_df.loc[cur_year_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn]
cur_year_profit = cur_year_profit_df.sum().sum()
folio_report_data["cur_year_profit"] = float(cur_year_profit)
# 今年累积收益率
cur_year_profit_ratio = return_ratio_serise.loc[cur_year_date:]
# 月度回报
def year_month(x):
a = x.year
b = x.month
return str(a) + "/" + str(b)
profit_df_cp = profit_df.copy()
profit_df_cp["date"] = profit_df_cp.index
grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month))
sum_group = grouped.agg(np.sum)
month_sum = sum_group.sum(axis=1)
last_profit_ratio = return_ratio_df.loc[:cur_year_date, "cum_return_ratio"].values
cur_profit_ratio = return_ratio_df.loc[cur_year_date:, "cum_return_ratio"].values
if len(last_profit_ratio) <= 0:
cur_year_profit_ratio = cur_profit_ratio[-1] - 1
else:
cur_year_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1]
folio_report_data["cur_year_profit_ratio"] = float(cur_year_profit_ratio)
# 累积收益率
profit_df_cp["cumulative_return"] = return_ratio_serise.cumsum()
grouped_cumulative = profit_df_cp["cumulative_return"].groupby(profit_df_cp["date"].apply(year_month))
month_cumulative_return = grouped_cumulative.last()
cumulative_return= return_ratio_df["cum_return_ratio"].values[-1]
folio_report_data["contribution_decomposition"] = float(cumulative_return)
# 单个组合基金净值数据
def signal_fund_info_data(self, p_fund_id_list, p_order_df):
pass
# 组合数据
# 组合内单个基金净值数据 组合内基金持仓数据
result_fund_nav_info, result_fund_hoding_info = self.group_fund_basic_info_data(cur_folio_order_data, cur_folio_result_cnav_data, cumulative_profit, total_cost)
def get_group_data(self):
pass
# 拼接组合以及综合结果数据
folio_report_data["group_nav_info"] = result_fund_nav_info
folio_report_data["group_hoding_info"] = result_fund_hoding_info
# 对应指数数据
index_df = self.get_customer_index_nav_data()
index_result = self.signal_fund_profit_result(index_df[index_df.index >= pd.to_datetime(first_trade_date)],
"index")
folio_report_data["index_result"] = index_result
self.group_result_data[folio] = folio_report_data
return self.group_result_data
# 综述数据
def calculate_total_data(self):
report_data = {}
cur_folio_result_cnav_data = self.total_customer_order_cnav_df
cur_folio_order_data = self.user_customer_order_df
freq_max = cur_folio_order_data["freq"].max()
#
fund_id_list = list(cur_folio_order_data["fund_id"].unique())
fund_id_list_earn = [i + "_earn" for i in fund_id_list]
profit_df = cur_folio_result_cnav_data[fund_id_list_earn]
# 持仓周期
first_trade_date = cur_folio_order_data["confirm_share_date"].min()
hold_days = (self.end_date - pd.to_datetime(first_trade_date)).days
report_data["hold_days"] = hold_days
# 组合收益率数组
return_ratio_df = self.combination_yield(cur_folio_result_cnav_data, fund_id_list)
resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max)
# 总成本
total_cost = float(cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_amount"].sum() - \
cur_folio_order_data[cur_folio_order_data["order_type"] == 2]["confirm_amount"].sum())
report_data["total_cost"] = total_cost
#
# # 累积盈利
# cumulative_profit = profit_df.sum().sum()
# report_data["cumulative_profit"] = float(cumulative_profit)
#
# # 区间年化收益
# n_freq = freq_days(int(freq_max))
# return_ratio_year = annual_return((resample_df["cum_return_ratio"].values[-1] - 1), resample_df, n_freq)
# report_data["return_ratio_year"] = float(return_ratio_year)
#
# # 波动率
# volatility_ = volatility(resample_df["cum_return_ratio"], n_freq)
# report_data["volatility"] = float(volatility_)
# 最大回撤
drawdown = max_drawdown(resample_df["cum_return_ratio"])
report_data["max_drawdown"] = drawdown
#
# # 夏普比率
# sim = simple_return(resample_df["cum_return_ratio"])
# exc = excess_return(sim, BANK_RATE, n_freq)
# sharpe = sharpe_ratio(exc, sim, n_freq)
# report_data["sharpe"] = float(sharpe)
#
# # 期末资产
# ending_assets = cumulative_profit + total_cost
# report_data["ending_assets"] = float(ending_assets)
#
# # 本月收益
# cur_month_profit_df = profit_df.loc[self.month_start_date:self.end_date + datetime.timedelta(days=1),
# fund_id_list_earn]
# cur_month_profit = cur_month_profit_df.sum().sum()
# report_data["cur_month_profit"] = float(cur_month_profit)
#
# # 本月累积收益率
# last_profit_ratio = return_ratio_df.loc[:self.month_start_date, "cum_return_ratio"].values
# cur_profit_ratio = return_ratio_df.loc[self.month_start_date:, "cum_return_ratio"].values
# if len(last_profit_ratio) <= 0:
# cur_month_profit_ratio = cur_profit_ratio[-1] - 1
# else:
# cur_month_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1]
# report_data["cur_month_profit_ratio"] = float(cur_month_profit_ratio)
#
# # 今年累积收益
# cur_year_date = pd.to_datetime(str(datetime.date(year=self.end_date.year, month=1, day=1)))
# cur_year_profit_df = profit_df.loc[cur_year_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn]
# cur_year_profit = cur_year_profit_df.sum().sum()
# report_data["cur_year_profit"] = float(cur_year_profit)
#
# # 今年累积收益率
# last_profit_ratio = return_ratio_df.loc[:cur_year_date, "cum_return_ratio"].values
# cur_profit_ratio = return_ratio_df.loc[cur_year_date:, "cum_return_ratio"].values
# if len(last_profit_ratio) <= 0:
# cur_year_profit_ratio = cur_profit_ratio[-1] - 1
# else:
# cur_year_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1]
# report_data["cur_year_profit_ratio"] = float(cur_year_profit_ratio)
# 月度回报
def year_month(x):
a = x.year
b = x.month
return str(a) + "/" + str(b)
profit_df_cp = profit_df.copy()
profit_df_cp["date"] = profit_df_cp.index
grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month))
sum_group = grouped.agg(np.sum)
month_sum = sum_group.sum(axis=1)
def performance_reward(self, order_info, ):
pass
return_ratio_df["date"] = return_ratio_df.index
return_group = return_ratio_df.groupby(return_ratio_df["date"].apply(year_month))
month_last_return_ratio = return_group.last()["cum_return_ratio"]
month_result = pd.DataFrame({"date": month_sum.index, "profit": month_sum.values, "ratio": month_last_return_ratio.values})
month_result["datetime"] = pd.to_datetime(month_result["date"])
month_result.sort_values(by="datetime", inplace=True)
report_data["month_return"] = month_result
# # 贡献分解
# month_earn = sum_group.div(month_sum, axis='rows')
# report_data["contribution_decomposition"] = month_earn
# 累积收益率
cumulative_return = return_ratio_df["cum_return_ratio"].values[-1]
report_data["contribution_decomposition"] = float(cumulative_return)
# 对应指数数据
index_df = self.get_customer_index_nav_data()
index_result = self.signal_fund_profit_result(index_df[index_df.index >= pd.to_datetime(first_trade_date)], "index")
report_data["index_result"] = index_result
self.total_result_data = report_data
return report_data
# 基金净值数据,持仓数据
def group_fund_basic_info_data(self, p_order_df, p_result_cnav_data, p_sum_profit, p_total_amount):
group_fund_basic_info = []
group_fund_hoding_info = []
for index, row in p_order_df.iterrows():
cur_fund_id = str(row["fund_id"])
cur_fund_performance = self.all_fund_performance[cur_fund_id]
cur_fund_info_series = cur_fund_performance.iloc[-1]
# 基金净值数据
fund_basic_info = {"fund_name": row["fund_name"], "confirm_nav": row["nav"]}
fund_basic_info["cur_nav"] = float(self.fund_nav_total[cur_fund_id].dropna().values[-1])
fund_basic_info["cur_cnav"] = float(self.fund_cnav_total[cur_fund_id].dropna().values[-1])
fund_basic_info["ret_1w"] = cur_fund_info_series["ret_1w"] # 上周
fund_basic_info["ret_cum_1m"] = cur_fund_info_series["ret_cum_1m"]
fund_basic_info["ret_cum_6m"] = cur_fund_info_series["ret_cum_6m"]
fund_basic_info["ret_cum_1y"] = cur_fund_info_series["ret_cum_1y"]
fund_basic_info["ret_cum_ytd"] = cur_fund_info_series["ret_cum_ytd"]
fund_basic_info["ret_cum_incep"] = cur_fund_info_series["ret_cum_incep"]
# 申购以来
confirm_date = pd.to_datetime(row["confirm_share_date"])
confirm_cnav = float(p_result_cnav_data.loc[confirm_date, cur_fund_id])
fund_basic_info["ret_after_confirm"] = (fund_basic_info["cur_cnav"] - confirm_cnav)/confirm_cnav
# 分红
distribution_df = self.all_fund_distribution[cur_fund_id]
if distribution_df.empty:
fund_basic_info["distribution"] = "-"
else:
distribution_df["price_date"] = pd.to_datetime(distribution_df["price_date"])
fund_basic_info["distribution"] = float(distribution_df[distribution_df["price_date"] > confirm_date]["distribution"].sum())
group_fund_basic_info.append(fund_basic_info)
# 基金持仓数据
fund_hoding_info = {"fund_strategy_name": dict_substrategy[int(row["substrategy"])], "fund_name": row["fund_name"]}
fund_hoding_info["confirm_date"] = row["confirm_share_date"]
fund_hoding_info["weight"] = float(row["confirm_amount"]) / p_total_amount
fund_hoding_info["market_values"] = float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav) + float(row["confirm_amount"])
fund_hoding_info["cost"] = float(row["confirm_amount"])
fund_hoding_info["profit"] = float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav)
# fund_hoding_info["ykb"] = fund_hoding_info["profit"] / fund_hoding_info["cost"]
try:
fund_hoding_info["ykb"] = float(gain_loss_ratio(p_result_cnav_data[cur_fund_id + "_profit"].dropna()))
except:
fund_hoding_info["ykb"] = 0
fund_hoding_info["profit_contribution"] = fund_hoding_info["profit"] / p_sum_profit
group_fund_hoding_info.append(fund_hoding_info)
return group_fund_basic_info, group_fund_hoding_info
@staticmethod
def combination_yield(p_combina_df, fund_id_list):
......@@ -146,7 +307,87 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor):
# 收益率
return_ratio = nav_profit_ratio_weight.sum(axis=1)
return return_ratio
# 累积收益率
return_ratio_list = list(return_ratio.values)
cum_return_ratio = []
last_ratio = 0
for i in range(len(return_ratio_list)):
if i == 0:
last_ratio = 1 + return_ratio_list[i]
cum_return_ratio.append(last_ratio)
continue
cur_ratio = (1 + return_ratio_list[i]) * last_ratio
cum_return_ratio.append(cur_ratio)
last_ratio = cur_ratio
# 收益率
cum_return_ratio_df = pd.DataFrame(return_ratio.values, columns=["return_ratio"])
cum_return_ratio_df["cum_return_ratio"] = cum_return_ratio
cum_return_ratio_df.index = return_ratio.index
return cum_return_ratio_df
@staticmethod
def signal_fund_profit_result(p_fund_nav_df, cur_fund_id):
result = {"fund_id": cur_fund_id}
fund_nav_df = p_fund_nav_df.copy()
profit = fund_nav_df[cur_fund_id].dropna() - fund_nav_df[cur_fund_id].dropna().shift(1)
fund_nav_df[cur_fund_id + "_profit"] = profit
fund_nav_df[cur_fund_id + "_profit_ratio"] = profit / fund_nav_df[cur_fund_id].dropna().shift(1)
# 累积收益率
return_ratio_list = list(fund_nav_df[cur_fund_id + "_profit_ratio"].astype("float64").values)
cum_return_ratio = []
last_ratio = 0
for i in range(len(return_ratio_list)):
if i == 0:
last_ratio = 1 + return_ratio_list[i] if str(return_ratio_list[0]) != 'nan' else 1
cum_return_ratio.append(last_ratio)
continue
cur_ratio = (1 + return_ratio_list[i]) * last_ratio
cum_return_ratio.append(cur_ratio)
last_ratio = cur_ratio
fund_nav_df['cum_return_ratio'] = cum_return_ratio
# 区间收益率
result["return_ratio"] = cum_return_ratio[-1]
# 区间年化收益
n_freq = freq_days(1)
return_ratio_year = annual_return((fund_nav_df["cum_return_ratio"].values[-1] - 1), fund_nav_df, n_freq)
result["return_ratio_year"] = float(return_ratio_year)
# 波动率
volatility_ = volatility(fund_nav_df["cum_return_ratio"], n_freq)
result["volatility"] = float(volatility_)
# 最大回撤
drawdown = max_drawdown(fund_nav_df["cum_return_ratio"])
result["max_drawdown"] = drawdown
# 夏普比率
sim = simple_return(fund_nav_df["cum_return_ratio"])
exc = excess_return(sim, BANK_RATE, n_freq)
sharpe = sharpe_ratio(exc, sim, n_freq)
result["sharpe"] = float(sharpe)
return result
def get_month_return_chart(self):
res = self.total_result_data["month_return"]
xlabels = res["date"].values
res["profit"] = res["profit"].apply(lambda x: round(x/100.0, 2))
res["ratio"] = res["ratio"].apply(lambda x: round((x-1)*100, 2))
product_list = {'name': '月度回报', 'data': res["profit"].values}
cumulative = {'name': '累积收益', 'data': res["ratio"].values}
return xlabels, [product_list], cumulative
def get_total_basic_data(self):
return self.total_result_data
def get_group_data(self):
return self.group_result_data
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -14,7 +14,7 @@ from matplotlib.ticker import FuncFormatter
from matplotlib.font_manager import FontProperties
# 中文字体初始化
plt.rcParams['font.sans-serif']=['Heiti TC']
plt.rcParams['font.sans-serif']=['SimSun']
def to_percent(temp, position):
......@@ -31,7 +31,7 @@ def draw_month_return_chart(xlabels, product_list, cumulative):
fontsize = 20
# 初始化
fig = plt.figure(figsize=figsize)
ax1 = fig.add_subplot()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
max_x_count = max([x['data'].size for x in product_list])
loc = np.arange(max_x_count) # the x locations for the groups
......
......@@ -11,6 +11,13 @@ import calendar
import math
dict_substrategy = {1010: '主观多头', 1020: '股票多空', 1030: '量化多头', 2010: '宏观策略', 3010: '主观趋势', 3020: '主观套利',
3030: '量化趋势', 3040: '量化套利', 3050: 'CTA策略', 4010: '并购重组', 4020: '定向增发', 4030: '大宗交易',
4040: '事件驱动复合', 5010: '市场中性', 5020: '套利策略', 5030: '相对价值复合', 6010: '纯债策略', 6020: '强债策略',
6030: '债券策略', 7010: 'MOM', 7020: 'FOF', 8010: '主观多策略', 8020: '量化多策略', -1: '其他策略'}
BANK_RATE = 0.015
def simple_return(net_worth):
"""
简单收益率
......@@ -272,4 +279,43 @@ def freq_days(fav_freq):
N = 3 # 季度更新
else:
N = 250 # 没有设置freq默认是天更
return N
\ No newline at end of file
return N
def resample(df, trading_cal, freq):
"""对基金净值表进行粒度不同的重采样,并剔除不在交易日中的结果
Args:
df ([DataFrame]): [原始基金净值表]
trading_cal ([type]): [上交所交易日表]
freq ([type]): [重采样频率: 1:工作日,2:周, 3:月, 4:半月, 5:季度]
Returns:
[DataFrame]: [重采样后剔除不在交易日历中的净值表和交易日历以净值日期为索引的合表]
"""
freq_dict = {1: 'B', 2: 'W-FRI', 3: 'M', 4: 'SM', 5: 'Q'}
resample_freq = freq_dict[freq]
# 按采样频率进行重采样并进行净值的前向填充
df = df.resample(rule=resample_freq).ffill()
# 根据采样频率确定最大日期偏移量(保证偏移后的日期与重采样的日期在同一周,同一月,同一季度等)
timeoffset_dict = {1: 1, 2: 5, 3: 30, 4: 15, 5: 120}
timeoffetmax = timeoffset_dict[freq]
# Dataframe不允许直接修改index,新建一份index的复制并转为list
new_index = list(df.index)
# 遍历重采样后的日期
for idx, date in enumerate(df.index):
# 如果重采样后的日期不在交易日历中
if date not in trading_cal.index:
# 对重采样后的日期进行偏移
for time_offset in range(1, timeoffetmax):
# 如果偏移后的日期在交易日历中,保留偏移后的日期
if date - datetime.timedelta(days=time_offset) in trading_cal.index:
new_index[idx] = date - datetime.timedelta(days=time_offset)
# 任意一天满足立即退出循环
break
# 更改净值表的日期索引为重采样后且在交易日内的日期
df.index = pd.Series(new_index)
return df
# -*- encoding: utf-8 -*-
# -----------------------------------------------------------------------------
# @File Name : html_to_pdf.py
# @Time : 2020/11/19 上午11:07
# @Author : X. Peng
# @Email : acepengxiong@163.com
# @Software : PyCharm
# -----------------------------------------------------------------------------
import pdfkit
from PyPDF2 import PdfFileMerger, PdfFileReader, PdfFileWriter
def html_to_pdf():
options = {
'--enable-local-file-access': '--enable-local-file-access',
# 'encoding': "utf-8",
# 'page-size': 'A5',
# 'page-width': '300mm',
# 'page-height': '200mm',
# 'margin-top': '0mm',
# 'margin-right': '0mm',
# 'margin-bottom': '0mm',
# 'margin-left': '0mm'
}
url1 = 'https://www.jianshu.com'
# url = 'http://baidu.com'
url2 = 'https://manage.meerkat.top'
# pdfkit.from_url(url1, '../pdf/out5.pdf', options=options)
# pdfkit.from_file('../templates/monthReport.html', '../pdf/out5.pdf', options=options)
pdfkit.from_file('app/html/monthReport.html', 'app/pdf/out5.pdf', options=options)
def merge_pdf(pdfFiles, target_file='/Users/pengxiong/Desktop/combine.pdf'):
""""""
merger = PdfFileMerger()
pdfWriter = PdfFileWriter() # 生成一个空白的pdf文件
for fileName in pdfFiles:
pdfReader = PdfFileReader(open(fileName, 'rb')) # 以只读方式依次打开pdf文件
for pageNum in range(pdfReader.numPages):
print(pdfReader.getPage(pageNum))
pdfWriter.addPage(pdfReader.getPage(pageNum)) # 将打开的pdf文件内容一页一页的复制到新建的空白pdf里
pdfOutput = open(target_file, 'wb') # 生成combine.pdf文件
pdfWriter.write(pdfOutput) # 将复制的内容全部写入combine.pdf
if __name__ == '__main__':
html_to_pdf()
# merge_pdf(['/Users/pengxiong/Desktop/out1.pdf', '/Users/pengxiong/Desktop/out.pdf'])
from jinja2 import PackageLoader, Environment
from app.service.result_service import UserCustomerResultAdaptor
# 准备数据
ifa_id = 'USER_INFO15914346866762'
customer_id = '202009281545001'
user_customer = UserCustomerResultAdaptor(ifa_id, customer_id)
df = user_customer.calculate_total_data()
d = user_customer.calculate_group_result_data()
print(d)
# 几月综述部分
total_cost = df["total_cost"]/10000
now_yield = round((df['contribution_decomposition']-1)*100,2)
index_yield = round((df["index_result"]["return_ratio"]-1)*100, 2)
now_withdrawal = round(df["max_drawdown"][0]*100,2)
index_withdrawal = round(df["index_result"]["max_drawdown"][0]*100, 2)
monthly_return_performance_pic = '_'.join((ifa_id, customer_id, '20201109', 'monthly_return_performance.png'))
image_dir = './img/'
monthly_return_performance_pic = image_dir + monthly_return_performance_pic
# 组合数据
group_result = d["default"]
now_month_income = int(group_result["cur_month_profit"]) # 本月收益
now_year_income = int(group_result["cur_year_profit"]) # 今年累计收益
totoal_rate_of_return = round((group_result['contribution_decomposition']-1)*100, 2) # 累计收益率
month_rise = round(group_result["cur_month_profit_ratio"]*100, 2) # 本月涨幅
year_totoal_rate_of_return = round(group_result["cur_year_profit_ratio"]*100, 2) # 今年累计收益率
annualised_return = round(group_result["return_ratio_year"]*100, 2) # 年化收益率
volatility = round(group_result["volatility"]*100, 2)
max_withdrawal = round(group_result["max_drawdown"][0]*100, 2)
sharpe_ratio = round(group_result["sharpe"], 2)
cost_of_investment = int(group_result["total_cost"]) # 投资成本
final_balance = int(group_result["total_cost"] + group_result["cumulative_profit"]) # 期末资产
total_profit = int(group_result["cumulative_profit"]) # 累计盈利
index_section_return = round((group_result["index_result"]["return_ratio"]-1)*100, 2)
index_annualised_return = round(group_result["index_result"]["return_ratio_year"]*100, 2) # 年化收益率
index_volatility = round(group_result["index_result"]["volatility"]*100, 2)
index_max_withdrawal = round(group_result["index_result"]["max_drawdown"][0]*100, 2)
index_sharpe_ratio = round(group_result["index_result"]["sharpe"], 2)
# 全部数据
data = {'customer_name':'成龙', 'customer_gender':'女',
'year_month':'2020年10月', 'ifa_company':'飞度工作室',
'title':'10月综述', 'brand_name':'飞度工作室',
'customer_old':42, 'customer_level':'平衡型',
'position_years':'5年', 'planned_allocation_amount':2000.00,
'now_allocation_amount':total_cost, 'now_yield':now_yield, 'index_yield':index_yield, 'expected_yield':20,
'now_withdrawal':now_withdrawal, 'index_withdrawal': index_withdrawal, 'expected_withdrawal': 20,
'now_year_income':now_year_income,'now_month_income':now_month_income,'totoal_rate_of_return':totoal_rate_of_return,
'month_rise':month_rise, 'year_totoal_rate_of_return':year_totoal_rate_of_return,
'annualised_return': annualised_return, 'cost_of_investment': cost_of_investment,
'final_balance':final_balance, 'total_profit':total_profit,
'latest_worth_day':'2020-11-05',
'index_comparison':{'section_return': totoal_rate_of_return, 'annualized_returns': annualised_return,
'volatility':volatility, 'max_withdrawal':max_withdrawal, 'sharpe_ratio': sharpe_ratio},
'index_comparison_500':{'section_return':index_section_return, 'annualized_returns': index_annualised_return,
'volatility':index_volatility, 'max_withdrawal':index_max_withdrawal, 'sharpe_ratio':index_sharpe_ratio},
'monthly_return_performance_pic':monthly_return_performance_pic,
}
# 开始渲染html模板
env = Environment(loader=PackageLoader('app','templates')) # 创建一个包加载器对象
template = env.get_template('monthReport.html') # 获取一个模板文件
monthReport_html = template.render(data) # 渲染
# 保存 monthReport_html
save_file = "app/html/monthReport.html"
with open(save_file, 'w', encoding="utf-8") as f:
f.write(monthReport_html)
\ No newline at end of file
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