def v_category_positions(self, date=yesterdayobj(), rendered=True): """ 资产分类扇形图,按大类资产求和绘制 :param date: :param rendered: bool. default true for notebook, for plain pyechart obj to return, set rendered=False :return: """ d = {} for f in self.fundtradeobj: if isinstance(f, itrade): t = f.get_type() if t == "场内基金": t = get_fund_type(f.code[2:]) elif f.code == "mf": t = "货币基金" else: t = get_fund_type(f.code) if t == "其他": logger.warning( "%s has category others which should be double checked" % f.code ) d[t] = d.get(t, 0) + f.briefdailyreport(date).get("currentvalue", 0) sdata = sorted([(k, round(v, 2)) for k, v in d.items()]) pie = Pie() pie.add( series_name="总值占比", data_pair=sdata, label_opts=opts.LabelOpts(is_show=False, position="center"), ).set_global_opts( legend_opts=opts.LegendOpts( pos_left="left", type_="scroll", orient="vertical" ) ).set_series_opts( tooltip_opts=opts.TooltipOpts( trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)" ), ) if rendered: return pie.render_notebook() else: return pie
def v_correlation(self, end=yesterdayobj(), vopts=None): """ 各基金净值的相关程度热力图可视化 :param end: string or object of date, the end date of the line :returns: pyecharts.charts.Heatmap.render_notebook object """ ctable = self.correlation_table(end) x_axis = list(ctable.columns) data = [[i, j, ctable.iloc[i, j]] for i in range(len(ctable)) for j in range(len(ctable))] heatmap = HeatMap() heatmap.add_xaxis(x_axis) heatmap.add_yaxis(series_name="相关性", yaxis_data=x_axis, value=data) if vopts is None: vopts = heatmap_opts heatmap.set_global_opts(**vopts) return heatmap.render_notebook()
def sellout(self, date=yesterdayobj(), ratio=1): ''' Sell all the funds in the same ratio on certain day, it is a virtual process, so it can happen before the last action exsiting in the cftable, by sell out earlier, it means all actions behind vanish. The status table in self.status would be directly changed. :param date: string or datetime obj of the selling date :param ratio: float between 0 to 1, the ratio of selling for each funds ''' date = convert_date(date) s = self.status[self.status['date'] <= date] row = [] ratio = ratio * 0.005 for term in s.columns: if term != 'date': row.append(-ratio) else: row.append(date) s = s.append(pd.DataFrame([row], columns=s.columns), ignore_index=True) self.status = s
def update(self): lastdate = self.price.iloc[-1].date lastdatestr = lastdate.strftime('%Y%m%d') weight = self.price.iloc[1].totvalue self._updateurl = 'http://quotes.money.163.com/service/chddata.html?code=' + \ self.code + '&start=' + lastdatestr + '&end=' + yesterday() + '&fields=TCLOSE' df = pd.read_csv(self._updateurl, encoding='gb2312') self.name = df.iloc[0].loc['名称'] if len(df) > 1: df = df.rename(columns={'收盘价': 'totvalue'}) df['date'] = pd.to_datetime(df.日期) df = df.drop(['股票代码', '名称', '日期'], axis=1) df['netvalue'] = df.totvalue / weight df['comment'] = [0 for _ in range(len(df))] df = df.iloc[::-1].iloc[1:] df = df[df['date'].isin(opendate)] df = df.reset_index(drop=True) df = df[df['date'] <= yesterdayobj()] self.price = self.price.append(df, ignore_index=True, sort=True) return df
def v_techindex(self, end=yesterdayobj(), col=None, **vkwds): ''' visualization on netvalue curve and specified indicators :param end: date string or obj, the end date of the figure :param col: list, list of strings for price col name, eg.['MA5','BBI'] remember generate these indicators before the visualization :param vkwds: keywords option for pyecharts.Line().add(). eg, you may need is_symbol_show=False to hide the symbols on lines ''' partprice = self.price[self.price['date'] <= end] xdata = [1 for _ in range(len(partprice))] netvaldata = [[row['date'], row['netvalue']] for _, row in partprice.iterrows()] line = Line() line.add('netvalue', xdata, netvaldata, is_datazoom_show=True, xaxis_type="time", **vkwds) if col is not None: for ind in col: inddata = [[row['date'], row[ind]] for _, row in partprice.iterrows()] line.add(ind, xdata, inddata, is_datazoom_show=True, xaxis_type="time", **vkwds) return line
def v_totvalue(self, end=yesterdayobj(), vopts=None): """ visualization on the total values daily change of the aim """ partp = self.aim.price[self.aim.price["date"] >= self.cftable.iloc[0].date] partp = partp[partp["date"] <= end] date = [d.date() for d in partp.date] valuedata = [ self.briefdailyreport(d).get("currentvalue", 0) for d in partp.date ] line = Line() if vopts is None: vopts = line_opts line.add_xaxis(date) line.add_yaxis(series_name="持仓总值", y_axis=valuedata, is_symbol_show=False) line.set_global_opts(**vopts) return line.render_notebook()
def v_totvalue(self, end=yesterdayobj(), **vkwds): ''' visualization on the total values daily change of the aim ''' valuedata = [] partp = self.aim.price[ self.aim.price['date'] >= self.cftable.iloc[0].date] partp = partp[partp['date'] <= end] for i, row in partp.iterrows(): date = row['date'] valuedata.append( [date, self.briefdailyreport(date).get('currentvalue', 0)]) line = Line() line.add('totvalue', [1 for _ in range(len(valuedata))], valuedata, is_datazoom_show=True, xaxis_type="time", **vkwds) return line
def update(self): lastdate = self.price.iloc[-1].date lastdatestr = lastdate.strftime("%Y%m%d") weight = self.price.iloc[1].totvalue self._updateurl = ( "http://quotes.money.163.com/service/chddata.html?code=" + self.code + "&start=" + lastdatestr + "&end=" + yesterday() + "&fields=TCLOSE") df = pd.read_csv(self._updateurl, encoding="gb2312") self.name = df.iloc[0].loc["名称"] if len(df) > 1: df = df.rename(columns={"收盘价": "totvalue"}) df["date"] = pd.to_datetime(df.日期) df = df.drop(["股票代码", "名称", "日期"], axis=1) df["netvalue"] = df.totvalue / weight df["comment"] = [0 for _ in range(len(df))] df = df.iloc[::-1].iloc[1:] df = df[df["date"].isin(opendate)] df = df.reset_index(drop=True) df = df[df["date"] <= yesterdayobj()] self.price = self.price.append(df, ignore_index=True, sort=True) return df
def briefdailyreport(self, date=yesterdayobj()): """ quick summary of highly used attrs for trade :param date: string or object of datetime :returns: dict with several attrs: date, unitvalue, currentshare, currentvalue """ date = convert_date(date) partcftb = self.cftable[self.cftable["date"] <= date] if len(partcftb) == 0: return {} unitvalue = self.get_netvalue(date) currentshare = myround(sum(partcftb.loc[:, "share"])) currentvalue = myround(currentshare * unitvalue) return { "date": date, "unitvalue": unitvalue, "currentshare": currentshare, "currentvalue": currentvalue, }
def v_positions(self, date=yesterdayobj(), rendered=True, vopts=None): """ pie chart visualization of positions ratio in combination """ sdata = sorted( [ (fob.name, fob.briefdailyreport(date).get("currentvalue", 0)) for fob in self.fundtradeobj ], key=lambda x: x[1], reverse=True, ) pie = Pie() if vopts is None: vopts = pie_opts pie.add(series_name="总值占比", data_pair=sdata) pie.set_global_opts(**vopts) if rendered: return pie.render_notebook() else: return pie
def v_correlation(self, end=yesterdayobj(), **vkwds): ''' 各基金净值的相关程度热力图可视化 :param end: string or object of date, the end date of the line :returns: pyecharts.Heatmap object ''' ctable = self.correlation_table(end) x_axis = list(ctable.columns) data = [[i, j, ctable.iloc[i, j]] for i in range(len(ctable)) for j in range(len(ctable))] heatmap = HeatMap() heatmap.add("", x_axis, x_axis, data, is_visualmap=True, visual_pos='center', visual_text_color="#000", visual_range=[-1, 1], visual_orient='horizontal', **vkwds) return heatmap
def v_netvalue(self, end=yesterdayobj(), vopts=None): """ 起点对齐归一的,各参考基金或指数的净值比较可视化 :param end: string or object of date, the end date of the line :param vkwds: pyechart line.add() options :param vopts: dict, options for pyecharts instead of builtin settings :returns: pyecharts.charts.Line.render_notebook() """ partprice = self.totprice[self.totprice["date"] <= end] line = Line() if vopts is None: vopts = line_opts line.set_global_opts(**vopts) line.add_xaxis([d.date() for d in list(partprice.date)]) for fund in self.fundobjs: line.add_yaxis( series_name=fund.name, y_axis=list(partprice[fund.code]), is_symbol_show=False, ) return line.render_notebook()
def briefdailyreport(self, date=yesterdayobj()): ''' quick summary of highly used attrs for trade :param date: string or object of datetime :returns: dict with several attrs: date, unitvalue, currentshare, currentvalue ''' date = convert_date(date) partcftb = self.cftable[self.cftable['date'] <= date] if len(partcftb) == 0: return {} unitvalue = self.aim.price[ self.aim.price['date'] <= date].iloc[-1].netvalue currentshare = myround(sum(partcftb.loc[:, 'share'])) currentvalue = myround(currentshare * unitvalue) return { 'date': date, 'unitvalue': unitvalue, 'currentshare': currentshare, 'currentvalue': currentvalue }
def v_positions(self, date=yesterdayobj(), rendered=True): """ pie chart visualization of positions ratio in combination """ sdata = sorted( [(fob.name, fob.briefdailyreport(date).get("currentvalue", 0)) for fob in self.fundtradeobj], key=lambda x: x[1], reverse=True, ) pie = Pie() pie.add( series_name="总值占比", data_pair=sdata, label_opts=opts.LabelOpts(is_show=False, position="center"), ).set_global_opts(legend_opts=opts.LegendOpts( pos_left="left", type_="scroll", orient="vertical")).set_series_opts(tooltip_opts=opts.TooltipOpts( trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"), ) if rendered: return pie.render_notebook() else: return pie
def v_netvalue(self, end=yesterdayobj(), **vkwds): ''' 起点对齐归一的,各参考基金或指数的净值比较可视化 :param end: string or object of date, the end date of the line :param vkwds: pyechart line.add() options :returns: pyecharts.Line object ''' partprice = self.totprice[self.totprice['date'] <= end] xdata = [1 for _ in range(len(partprice))] ydatas = [] for fund in self.fundobjs: ydata = [[row['date'], row[fund.code]] for _, row in partprice.iterrows()] ydatas.append(ydata) line = Line() for i, fund in enumerate(self.fundobjs): line.add(fund.name, xdata, ydatas[i], is_datazoom_show=True, xaxis_type="time", **vkwds) return line
def v_techindex(self, end=yesterdayobj(), col=None, vopts=None): """ visualization on netvalue curve and specified indicators :param end: date string or obj, the end date of the figure :param col: list, list of strings for price col name, eg.['MA5','BBI'] remember generate these indicators before the visualization, these cols don't automatically generate for visualization :param vopts: dict, options for pyecharts instead of builtin settings """ partprice = self.price[self.price["date"] <= end] xdata = [d.date() for d in list(partprice.date)] netvaldata = list(partprice.netvalue) if vopts is None: vopts = line_opts line = Line() line.add_xaxis(xdata) line.add_yaxis(series_name="netvalue", y_axis=netvaldata, is_symbol_show=False) line.set_global_opts(**vopts) if col is not None: for ind in col: inddata = list(partprice[ind]) line.add_yaxis(series_name=ind, y_axis=inddata, is_symbol_show=False) return line.render_notebook()
def v_netvalue(self, end=yesterdayobj(), benchmark=True, vopts=None): """ visulaization on netvalue curve :param end: dateobject for indicating the end date in the figure, default to yesterday :param benchmark: bool, whether include benchmark's netvalue curve, default true :param vopts: dict, options for pyecharts instead of builtin settings """ a, b = self.comparison(end) if vopts is None: vopts = line_opts line = Line() line.add_xaxis([d.date() for d in list(a.date)]) line.add_yaxis( y_axis=list(a.netvalue), series_name=self.name, is_symbol_show=False ) line.set_global_opts(**vopts) if benchmark is True: line.add_yaxis( series_name=self.benchmark.name, y_axis=list(b.netvalue), is_symbol_show=False, ) return line.render_notebook()
def total_annualized_returns(self, date=yesterdayobj()): return indicator.annualized_returns(self.price, self.start, date)
def sharpe(self, date=yesterdayobj()): rp = self.total_annualized_returns(date) return (rp - self.riskfree) / self.algorithm_volatility(date)
def algorithm_volatility(self, date=yesterdayobj()): return indicator.volatility(self.price, date)
def benchmark_volatility(self, date=yesterdayobj()): return indicator.volatility(self.bmprice, date)
def alpha(self, date=yesterdayobj()): rp = self.total_annualized_returns(date) rm = self.benchmark_annualized_returns(date) beta = self.beta(date) return rp - (self.riskfree + beta * (rm - self.riskfree))
def volatility(price, date=yesterdayobj()): df = pd.DataFrame(data={"rate": indicator.ratedaily(price, date)}) return df.std().rate * 15.8144
def benchmark_annualized_returns(self, date=yesterdayobj()): return indicator.annualized_returns(self.bmprice, self.start, date)
def beta(self, date=yesterdayobj()): bcmk = indicator.ratedaily(self.bmprice, date) bt = indicator.ratedaily(self.price, date) df = pd.DataFrame(data={"bcmk": bcmk, "bt": bt}) res = df.cov() return res.loc["bcmk", "bt"] / res.loc["bcmk", "bcmk"]
def _addrow(self): """ Return cashflow table with one more line or raise an exception if there is no more line to add The same logic also applies to rem table 关于对于一个基金多个操作存在于同一交易日的说明:无法处理历史买入第一笔同时是分红日的情形, 事实上也不存在这种情形。无法处理一日多笔买卖的情形。 同一日既有卖也有买不现实,多笔买入只能在 csv 上合并记录,由此可能引起份额计算 0.01 的误差。可以处理分红日买入卖出的情形。 分级份额折算日封闭无法买入,所以程序直接忽略当天的买卖。因此不会出现多个操作共存的情形。 """ # the design on data remtable is disaster, it is very dangerous though works now code = self.aim.code if len(self.cftable) == 0: if len(self.status[self.status[code] != 0]) == 0: raise Exception("no other info to be add into cashflow table") i = 0 while self.status.iloc[i].loc[code] == 0: i += 1 value = self.status.iloc[i].loc[code] date = self.status.iloc[i].date if value > 0: rdate, cash, share = self.aim.shengou(value, date) rem = rm.buy([], share, rdate) else: raise TradeBehaviorError("You cannot sell first when you never buy") elif len(self.cftable) > 0: recorddate = list(self.status.date) lastdate = self.cftable.iloc[-1].date + pd.Timedelta(1, unit="d") while (lastdate not in self.aim.specialdate) and ( (lastdate not in recorddate) or ( (lastdate in recorddate) and ( self.status[self.status["date"] == lastdate].loc[:, code].any() == 0 ) ) ): lastdate += pd.Timedelta(1, unit="d") if (lastdate - yesterdayobj()).days >= 1: raise Exception("no other info to be add into cashflow table") date = lastdate label = self.aim.dividend_label # 现金分红 0, 红利再投 1 cash = 0 share = 0 rem = self.remtable.iloc[-1].rem rdate = date if (date in recorddate) and (date not in self.aim.zhesuandate): # deal with buy and sell and label the fenhongzaitouru, namely one label a 0.05 in the original table to label fenhongzaitouru value = self.status[self.status["date"] == date].iloc[0].loc[code] fenhongmark = round(10 * value - int(10 * value), 1) if fenhongmark == 0.5 and label == 0: label = 1 # fenhong reinvest value = round(value, 1) elif fenhongmark == 0.5 and label == 1: label = 0 value = round(value, 1) if value > 0: # value stands for purchase money rdate, dcash, dshare = self.aim.shengou(value, date) rem = rm.buy(rem, dshare, rdate) elif value < -0.005: # value stands for redemp share rdate, dcash, dshare = self.aim.shuhui( -value, date, self.remtable.iloc[-1].rem ) _, rem = rm.sell(rem, -dshare, rdate) elif value >= -0.005 and value < 0: # value now stands for the ratio to be sold in terms of remain positions, -0.005 stand for sell 100% remainshare = sum(self.cftable.loc[:, "share"]) ratio = -value / 0.005 rdate, dcash, dshare = self.aim.shuhui( remainshare * ratio, date, self.remtable.iloc[-1].rem ) _, rem = rm.sell(rem, -dshare, rdate) else: # in case value=0, when specialday is in record day rdate, dcash, dshare = date, 0, 0 cash += dcash share += dshare if date in self.aim.specialdate: # deal with fenhong and xiazhe comment = ( self.aim.price[self.aim.price["date"] == date] .iloc[0] .loc["comment"] ) if isinstance(comment, float): if comment < 0: dcash2, dshare2 = ( 0, sum([myround(sh * (-comment - 1)) for _, sh in rem]), ) # xiazhe are seperately carried out based on different purchase date rem = rm.trans(rem, -comment, date) # myround(sum(cftable.loc[:,'share'])*(-comment-1)) elif comment > 0 and label == 0: dcash2, dshare2 = ( myround(sum(self.cftable.loc[:, "share"]) * comment), 0, ) rem = rm.copy(rem) elif comment > 0 and label == 1: dcash2, dshare2 = ( 0, myround( sum(self.cftable.loc[:, "share"]) * ( comment / self.aim.price[self.aim.price["date"] == date] .iloc[0] .netvalue ) ), ) rem = rm.buy(rem, dshare2, date) cash += dcash2 share += dshare2 else: raise ParserFailure("comments not recoginized") self.cftable = self.cftable.append( pd.DataFrame([[rdate, cash, share]], columns=["date", "cash", "share"]), ignore_index=True, ) self.remtable = self.remtable.append( pd.DataFrame([[rdate, rem]], columns=["date", "rem"]), ignore_index=True )
def get_netvalue(self, date=yesterdayobj()): return get_daily(self.code, end=date.strftime("%Y%m%d"), prev=20).iloc[-1].close
def v_tradecost(self, start=None, end=yesterdayobj(), vopts=None): raise NotImplementedError()
def v_totvalue(self, end=yesterdayobj(), vopts=None): raise NotImplementedError()
def get_netvalue(self, date=yesterdayobj()): return self.aim.price[self.aim.price["date"] <= date].iloc[-1].netvalue