def get_t0(self, return_date=True, percent=False): last_value, last_date = self.get_t1() last_date_obj = dt.datetime.strptime(last_date, "%Y-%m-%d") cday = last_onday(self.today) while last_date_obj < cday: # 昨天净值数据还没更新 # 是否存在部分部分基金可能有 gap? if cday.strftime("%Y-%m-%d") not in gap_info[self.fcode]: self.t1_type = "昨日未出" raise DateMismatch( self.code, reason="%s netvalue has not been updated to yesterday" % self.code, ) else: cday = last_onday(cday) # 经过这个没报错,就表示数据源是最新的 if last_date_obj >= self.today: # 今天数据已出,不需要再预测了 print("no need to predict net value since it has been out for %s" % self.code) self.t1_type = "今日已出" if not return_date: return last_value else: return last_value, last_date t = 0 n = 0 today_str = self.today.strftime("%Y%m%d") for k, v in self.t0dict.items(): w = v t += w r = get_rt(k) # k should support get_rt, investing pid doesn't support this! if percent: c = w / 100 * (1 + r["percent"] / 100) # 直接取标的当日涨跌幅 else: df = xu.get_daily(k) basev = df[df["date"] <= last_date].iloc[-1]["close"] c = w / 100 * r["current"] / basev currency_code = get_currency_code(k) if currency_code: c = c * daily_increment(currency_code, today_str) n += c n += (100 - t) / 100 t0value = n * last_value self.t0_delta = n if not return_date: return t0value else: return t0value, self.today.strftime("%Y-%m-%d")
def daily_increment(code, date, lastday=None, _check=False): """ 单一标的 date 日(若 date 日无数据则取之前的最晚有数据日,但该日必须大于 _check 对应的日期)较上一日或 lastday 的倍数, lastday 支持不完整,且不能离 date 太远 :param code: :param date: :param lastday: 如果用默认 None,则表示和前一日的涨跌 :param _check: 数据必须已更新到 date 日,除非之前每天都是节假日 :return: """ try: tds = xu.get_daily(code=code, end=date, prev=30) except Exception as e: # 只能笼统 catch 了,因为抓取失败的异常是什么都能遇到。。。 code = get_alt(code) if code: tds = xu.get_daily(code=code, end=date, prev=30) else: raise e tds = tds[tds["date"] <= date] if _check: date = date.replace("-", "").replace("/", "") date_obj = dt.datetime.strptime(date, "%Y%m%d") while tds.iloc[-1]["date"] < date_obj: # in case data is not up to date # 但是存在日本市场休市时间不一致的情况,估计美股也存在 if not is_on( date_obj.strftime("%Y%m%d"), get_market(code), no_trading_days=no_trading_days, ) or (date_obj.strftime("%Y-%m-%d") in gap_info.get(code, [])): print("%s is closed on %s" % (code, date)) if not lastday: return 1 # 当日没有涨跌,这里暂时为考虑 _check 和 lastday 相同的的情形 date_obj -= dt.timedelta(days=1) else: raise DateMismatch( code, reason="%s has no data newer than %s" % (code, date_obj.strftime("%Y-%m-%d")), ) if not lastday: ratio = tds.iloc[-1]["close"] / tds.iloc[-2]["close"] else: tds2 = tds[tds["date"] <= lastday] # 未考虑连 lastday 的数据数据源都没更新的情形,这种可能极小 ratio = tds.iloc[-1]["close"] / tds2.iloc[-1]["close"] return ratio
def get_t1(self, date=None, return_date=True): """ 预测 date 日的净值,基于 date-1 日的净值和 date 日的外盘数据,数据自动缓存,不会重复计算 :param date: str. %Y-%m-%d. 注意若是 date 日为昨天,即今日预测昨日的净值,date 取默认值 None。 :param return_date: bool, default True. return tuple, the second one is date in the format %Y%m%d :return: float, (str). :raises NonAccurate: 由于外盘数据还未及时更新,而 raise,可在调用程序中用 except 捕获再处理。 """ if date is None: yesterday = last_onday(self.today) datekey = yesterday.strftime("%Y%m%d") else: datekey = date.replace("/", "").replace("-", "") if datekey not in self.t1value_cache: if self.positions: current_pos = self.get_position(datekey, return_date=False) hdict = scale_dict(self.t1dict.copy(), aim=current_pos * 100) else: hdict = self.t1dict.copy() if date is None: # 此时预测上个交易日净值 yesterday_str = datekey last_value, last_date = self.get_t2() last_date_obj = dt.datetime.strptime(last_date, "%Y-%m-%d") cday = last_onday(last_onday(self.today)) while last_date_obj < cday: # 前天净值数据还没更新 # 是否存在部分 QDII 在 A 股交易日,美股休市日不更新净值的情形? if (cday.strftime("%Y-%m-%d") not in gap_info[self.fcode]) and is_on( cday, "US", no_trading_days): # 这里检查比较宽松,只要当天美股休市,就可以认为确实基金数据不存在而非未更新 self.t1_type = "前日未出" raise DateMismatch( self.code, reason= "%s netvalue has not been updated to the day before yesterday" % self.code, ) else: cday = last_onday(cday) # 经过这个没报错,就表示数据源是最新的 if last_date_obj >= last_onday(self.today): # 昨天数据已出,不需要再预测了 print( "no need to predict t-1 value since it has been out for %s" % self.code) self.t1_type = "昨日已出" self.t1value_cache = { last_date.replace("-", ""): last_value } if not return_date: return last_value else: return last_value, last_date else: yesterday_str = datekey fund_price = xu.get_daily(self.fcode) # 获取国内基金净值 fund_last = fund_price[fund_price["date"] < date].iloc[-1] # 注意实时更新应用 date=None 传入,否则此处无法保证此数据是前天的而不是大前天的,因为没做校验 # 事实上这里计算的预测是针对 date 之前的最晚数据和之前一日的预测 last_value = fund_last["close"] last_date = fund_last["date"].strftime("%Y-%m-%d") self.t1_delta = (1 + evaluate_fluctuation( hdict, yesterday_str, lastday=last_date, _check=True) / 100) net = last_value * self.t1_delta self.t1value_cache[datekey] = net self.t1_type = "已计算" if not return_date: return self.t1value_cache[datekey] else: return ( self.t1value_cache[datekey], datekey[:4] + "-" + datekey[4:6] + "-" + datekey[6:8], )