Commit 745c54cb authored by pengxiong@wealthgrow.cn's avatar pengxiong@wealthgrow.cn

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

parents 1f273295 ab92ee39
...@@ -12,25 +12,32 @@ from sqlalchemy import and_ ...@@ -12,25 +12,32 @@ from sqlalchemy import and_
import tushare as ts import tushare as ts
import datetime import datetime
from app.api.engine import tamp_user_session, tamp_product_session from app.api.engine import tamp_user_session, tamp_product_session
# from app.model.tamp_user_models import t_customer_order, t_customer_info # from app.model.tamp_user_models import CustomerOrder, CustomerInfo
# from app.model.tamp_product_models import t_fund_info # from app.model.tamp_product_models import FundInfo
class UserCustomerDataAdaptor: class UserCustomerDataAdaptor:
user_id = "" user_id = ""
customer_id = "" customer_id = ""
start_date = "" month_date = ""
end_date = "" end_date = ""
group_data = {} group_data = {}
trade_cal = None
all_fund_distribution = {}
all_fund_performance = {}
def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())): def __init__(self, user_id, customer_id, end_date=str(datetime.date.today()), index_id="IN0000007M"):
self.user_id = user_id self.user_id = user_id
self.customer_id = customer_id self.customer_id = customer_id
self.compare_index_id = index_id
p_end_date = pd.to_datetime(end_date).date() 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) 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(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.user_customer_order_df = self.get_user_customer_order_data() self.user_customer_order_df = self.get_user_customer_order_data()
self.fund_nav_total = self.get_customer_fund_nav_data() self.fund_nav_total, self.fund_cnav_total = self.get_customer_fund_nav_data()
self.get_customer_index_nav_data() self.get_customer_index_nav_data()
self.group_operate() self.group_operate()
...@@ -45,12 +52,13 @@ class UserCustomerDataAdaptor: ...@@ -45,12 +52,13 @@ class UserCustomerDataAdaptor:
df.drop(['exchange', 'is_open'], axis=1, inplace=True) df.drop(['exchange', 'is_open'], axis=1, inplace=True)
df.rename(columns={'cal_date': 'end_date'}, inplace=True) df.rename(columns={'cal_date': 'end_date'}, inplace=True)
df["datetime"] = df["end_date"].apply(lambda x: datetime.datetime.strptime(x, "%Y%m%d")) df["datetime"] = df["end_date"].apply(lambda x: datetime.datetime.strptime(x, "%Y%m%d"))
return df return df
# 获取理财师下该用户所有订单列表 # 获取理财师下该用户所有订单列表
def get_user_customer_order_data(self): def get_user_customer_order_data(self):
# data1 = tamp_user_session.query(t_customer_order)\ # data1 = tamp_user_session.query(CustomerOrder)\
# .filter(user_id = self.user_id).all() # # .filter(user_id = self.user_id).all()
# data2 = tamp_user_session.query(t_customer_info).all() # data2 = tamp_user_session.query(t_customer_info).all()
# data3 = tamp_product_session.query(t_fund_info).all() # data3 = tamp_product_session.query(t_fund_info).all()
...@@ -74,7 +82,9 @@ class UserCustomerDataAdaptor: ...@@ -74,7 +82,9 @@ class UserCustomerDataAdaptor:
def get_customer_fund_nav_data(self): def get_customer_fund_nav_data(self):
now_date = datetime.datetime.now().strftime("%Y%m%d") now_date = datetime.datetime.now().strftime("%Y%m%d")
trade_date_df = self.get_trade_cal("20000101", now_date) trade_date_df = self.get_trade_cal("20000101", now_date)
self.trade_cal = trade_date_df
all_fund_nav = pd.DataFrame(index=trade_date_df["datetime"]) all_fund_nav = pd.DataFrame(index=trade_date_df["datetime"])
all_fund_cnav = pd.DataFrame(index=trade_date_df["datetime"])
for cur_fund_id in self.user_customer_order_df["fund_id"].unique(): for cur_fund_id in self.user_customer_order_df["fund_id"].unique():
# 对应基金净值 # 对应基金净值
...@@ -89,24 +99,35 @@ class UserCustomerDataAdaptor: ...@@ -89,24 +99,35 @@ class UserCustomerDataAdaptor:
# cur = tamp_product_session.execute(sql) # cur = tamp_product_session.execute(sql)
# data = cur.fetchall() # data = cur.fetchall()
# cur_fund_distribution_df = pd.DataFrame(list(data), columns=['price_date', 'distribution']) # 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
cur_fund_nav_df["price_date"] = pd.to_datetime(cur_fund_nav_df["price_date"]) 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) cur_fund_nav_df.set_index("price_date", inplace=True)
all_fund_nav[cur_fund_id] = cur_fund_nav_df["cnav"] all_fund_nav[cur_fund_id] = cur_fund_nav_df["nav"]
all_fund_cnav[cur_fund_id] = cur_fund_nav_df["cnav"]
all_fund_nav = all_fund_nav[all_fund_nav.index <= self.end_date] all_fund_nav = all_fund_nav[all_fund_nav.index <= self.end_date]
return all_fund_nav all_fund_cnav = all_fund_cnav[all_fund_cnav.index <= self.end_date]
return all_fund_nav, all_fund_cnav
# 获取客户对比指数净值数据 # 获取客户对比指数净值数据
def get_customer_index_nav_data(self, index_id="IN0000007M"): def get_customer_index_nav_data(self, index_id="IN0000007M"):
sql = "select distinct price_date,close from fund_market_indexes where index_id='{}' order by price_date ASC".format(index_id) sql = "select distinct price_date,close from fund_market_indexes where index_id='{}' order by price_date ASC".format(index_id)
cur = tamp_product_session.execute(sql) cur = tamp_product_session.execute(sql)
data = cur.fetchall() data = cur.fetchall()
index_df = pd.DataFrame(list(data), columns=['price_date', 'index']) index_df = pd.DataFrame(list(data), columns=['price_date', 'index'])
index_df["price_date"] = pd.to_datetime(index_df["price_date"]) index_df["price_date"] = pd.to_datetime(index_df["price_date"])
index_df.set_index("price_date", inplace=True) index_df.set_index("price_date", inplace=True)
self.fund_nav_total["index"] = index_df["index"] self.fund_cnav_total["index"] = index_df["index"]
return index_df return index_df
...@@ -116,36 +137,84 @@ class UserCustomerDataAdaptor: ...@@ -116,36 +137,84 @@ class UserCustomerDataAdaptor:
for folio in self.user_customer_order_df["folio_name"].unique(): 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] 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()) fund_id_list = list(self.user_customer_order_df["fund_id"].unique())
fund_id_list.append("index")
cur_folio_nav_df = self.fund_nav_total[fund_id_list] cur_folio_nav_df = self.fund_nav_total[fund_id_list]
self.signal_folio_operate(folio, cur_folio_order_df, cur_folio_nav_df) # fund_id_list.append("index")
cur_folio_cnav_df = self.fund_cnav_total[fund_id_list]
self.signal_folio_operate(folio, cur_folio_order_df, cur_folio_nav_df, cur_folio_cnav_df)
continue continue
# 单个组合数据操作 # 单个组合数据操作
def signal_folio_operate(self, p_folio, p_order_df, p_nav_df): def signal_folio_operate(self, p_folio, p_order_df, p_nav_df, p_cnav_df):
start_date = pd.to_datetime(p_order_df["confirm_share_date"].min()) start_date = pd.to_datetime(p_order_df["confirm_share_date"].min())
nav_df = p_nav_df[p_nav_df.index >= start_date].copy()
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(): for index, row in p_order_df.iterrows():
cur_fund_id = str(row["fund_id"]) cur_fund_id = str(row["fund_id"])
confirm_share_date = pd.to_datetime(row["confirm_share_date"]) confirm_share_date = pd.to_datetime(row["confirm_share_date"])
if cur_fund_id+"_amount" not in nav_df: # # 根据确认净值日查看是否含有累积净值的数据,如果没有按照前后差值推算当天累积净值
nav_df[cur_fund_id + "_profit"] = (nav_df[cur_fund_id].dropna() - nav_df[cur_fund_id].dropna().shift(1)) # if pd.isnull(cnav_df.loc[confirm_share_date, cur_fund_id]):
nav_df[cur_fund_id+"_amount"] = 0 # last_nav_data = p_nav_df[p_nav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1)
nav_df[cur_fund_id + "_earn"] = 0 # last_cnav_data = p_cnav_df[p_cnav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1)
nav_df[cur_fund_id + "_share"] = 0 # # 判断上个净值日和当前确认日之中是否存在分红日
# """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
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 # buy
if row['order_type'] == 1: if row['order_type'] == 1:
nav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] += row["confirm_amount"] cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] += row["confirm_amount"]
nav_df.loc[confirm_share_date:, cur_fund_id + "_share"] += row["confirm_share"] cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] += row["confirm_share"]
# sell # sell
elif row['order_type'] == 2: elif row['order_type'] == 2:
nav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] -= row["confirm_amount"] cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] -= row["confirm_amount"]
nav_df.loc[confirm_share_date:, cur_fund_id + "_share"] -= row["confirm_share"] cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] -= row["confirm_share"]
nav_df[cur_fund_id + "_earn"] = nav_df[cur_fund_id + "_profit"] * nav_df[cur_fund_id + "_share"] cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_profit"] * cnav_df[cur_fund_id + "_share"]
self.group_data[p_folio] = {"basic_data": nav_df} cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_earn"].apply(lambda x: float(x))
return nav_df cnav_df[cur_fund_id + "_cum_earn"] = cnav_df[cur_fund_id + "_earn"].cumsum()
self.group_data[p_folio] = {"result_cnav_data": cnav_df, "order_df": p_order_df}
return cnav_df
def total_combine_data(self):
pass
...@@ -9,18 +9,144 @@ ...@@ -9,18 +9,144 @@
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import datetime import datetime
from decimal import Decimal
from app.service.data_service import UserCustomerDataAdaptor 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): class UserCustomerResultAdaptor(UserCustomerDataAdaptor):
total_result_data = {}
group_result_data = []
def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())): def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())):
UserCustomerDataAdaptor.__init__(user_id, customer_id, end_date) # super().__init__()
super().__init__(user_id, customer_id, end_date)
# 综述数据 # 综述数据
def get_total_data(self): def get_total_data(self):
for folio in self.group_data.keys():
# self.group_result_data.append({folio: {}})
cur_folio_result_cnav_data = self.group_data[folio]["result_cnav_data"]
cur_folio_order_data = self.group_data[folio]["order_df"]
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]
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)
# 总成本
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())
# 累积盈利
cumulative_profit = profit_df.sum().sum()
# 年化收益
return_ratio_year = 0
"""*************************年化收益*******************************"""
# 期末资产
ending_assets = cumulative_profit + total_cost
# 本月收益
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()
# 本月累积收益率
cur_month_profit_ratio = return_ratio_serise.loc[self.month_start_date:].sum()
# 今年累积收益
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()
# 今年累积收益率
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)
# 累积收益率
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()
# 单个组合基金净值数据
def signal_fund_info_data(self, p_fund_id_list, p_order_df):
pass pass
# 组合数据
# 组合数据
def get_group_data(self): def get_group_data(self):
pass pass
def performance_reward(self, order_info, ):
pass
@staticmethod
def combination_yield(p_combina_df, fund_id_list):
fund_id_list_amount = [i + "_amount" for i in fund_id_list]
fund_id_list_profit_ratio = [i + "_profit_ratio" for i in fund_id_list]
nav_amount_df = p_combina_df[fund_id_list + fund_id_list_amount+fund_id_list_profit_ratio].copy()
nav_amount_df["sum_amount"] = nav_amount_df[fund_id_list_amount].sum(axis=1).apply(lambda x: Decimal.from_float(x))
for amount_name in fund_id_list:
nav_amount_df[amount_name+"_amount_ratio"] = nav_amount_df[amount_name+"_amount"]/nav_amount_df["sum_amount"]
nav_amount_df[amount_name+"_profit_ratio_weight"] = nav_amount_df[amount_name+"_amount_ratio"] * nav_amount_df[amount_name+"_profit_ratio"]
fund_id_list_profit_ratio_weight = [i + "_profit_ratio_weight" for i in fund_id_list]
nav_profit_ratio_weight = nav_amount_df[fund_id_list_profit_ratio_weight].copy().fillna(method='ffill')
# 收益率
return_ratio = nav_profit_ratio_weight.sum(axis=1)
return return_ratio
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