def ensure_dates_base_on_listed_date(instrument, start_date, end_date, market): from rqdatac.services.calendar import get_previous_trading_date, get_latest_trading_date if to_date(instrument.listed_date) > datetime.date.today(): raise ValueError("instrument {} is not listed yet".format( instrument.order_book_id)) if start_date is None: start_date = instrument.listed_date elif to_date(start_date) < to_date(instrument.listed_date): start_date = to_date(instrument.listed_date) elif instrument.de_listed_date != "0000-00-00" and to_date( start_date) >= to_date(instrument.de_listed_date): warnings.warn("{} has been delisted on {}".format( instrument.order_book_id, instrument.de_listed_date)) return None, None if end_date is None: if instrument.de_listed_date != "0000-00-00": end_date = get_previous_trading_date(instrument.de_listed_date, market=market) else: end_date = get_latest_trading_date(market=market) elif instrument.de_listed_date != "0000-00-00" and to_date( end_date) >= to_date(instrument.de_listed_date): warnings.warn("{} has been delisted on {}".format( instrument.order_book_id, instrument.de_listed_date)) end_date = get_previous_trading_date(instrument.de_listed_date, market=market) return start_date, end_date
def current_minute(order_book_ids, skip_suspended=False, fields=None, market="cn"): """获取实时分钟行情 :param order_book_ids: 合约代码或代码列表 :param skip_suspended: 是否过滤停复牌. (Default value = False) :param fields: 可选参数。默认为所有字段。 (Default value = None) :param market: 地区代码, 如'cn' (Default value = "cn") :returns: None or pd.DataFrame """ from rqdatac.services.get_price import classify_order_book_ids, _ensure_fields from rqdatac.services.detail.get_price_df import MINBAR_FIELDS (order_book_ids, stocks, funds, indexes, futures, futures888, spots, options, convertibles, repos) = classify_order_book_ids(order_book_ids, market) if skip_suspended and stocks: date = get_previous_trading_date(datetime.date.today() + datetime.timedelta(days=1)) df_suspended = is_suspended(stocks, date, date) if not df_suspended.empty: df_suspended_t = df_suspended.T suspended_obids = set(df_suspended_t[df_suspended_t[df_suspended_t.columns[0]]].index) inspection = suspended_obids & set(stocks) if inspection: stocks = set(stocks) - inspection order_book_ids = list(set(order_book_ids) - inspection) fields, _ = _ensure_fields(fields, MINBAR_FIELDS, stocks, funds, futures, futures888, spots, options, convertibles, indexes, repos) data = get_client().execute("current_minute", order_book_ids, fields + ["datetime"], market=market) if not data: return df = pd.DataFrame(data) df["datetime"] = df["datetime"].map(int14_to_datetime, na_action="ignore") df.set_index(["order_book_id", "datetime"], inplace=True) return df
def get_ksh_tickbar(order_book_id, start_date, end_date, fields, market): order_book_id = ensure_order_book_id(order_book_id) start_date, end_date = ensure_date_range(start_date, end_date, datetime.timedelta(days=3)) data = get_client().execute( "get_ksh_tickbar", order_book_id, start_date, end_date, fields, market ) today = today_int() if data: data = [(obid, {k: np.frombuffer(*v) for k, v in d.items()}) for obid, d in data] df_list = [] for obid, d in data: df = pd.DataFrame(d) df_list.append(df) df = pd.concat(df_list) # type: pd.DataFrame df["datetime"] = int17_to_datetime_v(df["datetime"].values) history_latest_date = date_to_int8(df.iloc[-1]["datetime"]) df.set_index("datetime", inplace=True) else: df = None history_latest_date = date_to_int8(get_previous_trading_date(today, market=market)) if history_latest_date >= end_date or start_date > today or history_latest_date >= today: return df live_df = get_today_ksh_tick(order_book_id, today, fields, market=market) if live_df is None: return df if df is None: return live_df return pd.concat([df, live_df])
def get_ksh_minbar(order_book_ids, start_date, end_date, fields, duration, market): data = get_client().execute( "get_ksh_minbar", order_book_ids, start_date, end_date, fields, duration, market ) if data: data = [(obid, {k: np.frombuffer(*v) for k, v in d.items()}) for obid, d in data] df = convert_bar_to_multi_df(data, 'datetime', fields, int14_to_datetime_v) else: df = None today = today_int() if df is None: history_latest_date = date_to_int8(get_previous_trading_date(today, market=market)) else: history_latest_date = date_to_int8(df.index.get_level_values(1).max()) if history_latest_date >= end_date or start_date > today or history_latest_date >= today: return df live_df = get_today_ksh_minbar(order_book_ids, today, fields, duration, market) if live_df is None: return df if df is None: return live_df df = pd.concat([df, live_df]) df.sort_index(inplace=True) return df
def get_capital_flow_tickbar(order_book_id, start_date, end_date, fields, market): ensure_string(order_book_id, "order_book_id") start_date, end_date = ensure_date_range(start_date, end_date, datetime.timedelta(days=3)) history_permission_denied = realtime_permission_denied = False try: data = get_client().execute("get_capital_flow_tickbar", order_book_id, start_date, end_date, fields, market=market) except PermissionDenied: data = [] history_permission_denied = True today = today_int() if data: data = [(obid, {k: np.frombuffer(*v) for k, v in d.items()}) for obid, d in data] df_list = [] for obid, d in data: df = pd.DataFrame(d) df_list.append(df) df = pd.concat(df_list) # type: pd.DataFrame df["datetime"] = int17_to_datetime_v(df["datetime"].values) history_latest_date = date_to_int8(df.iloc[-1]["datetime"]) df.set_index("datetime", inplace=True) else: df = None history_latest_date = date_to_int8( get_previous_trading_date(today, market=market)) if history_latest_date >= end_date or start_date > today or history_latest_date >= today: return df try: live_df = get_today_capital_flow_tick(order_book_id, today, market=market) except PermissionDenied: live_df = None realtime_permission_denied = True except MarketNotSupportError: live_df = None if history_permission_denied and realtime_permission_denied: raise PermissionDenied("get_capital_flow_tick") if live_df is None: return df if df is None: return live_df return pd.concat([df, live_df])
def ensure_trading_date(date): from rqdatac.services.calendar import get_trading_dates, get_previous_trading_date, get_next_trading_date trading_dates = get_trading_dates(get_previous_trading_date(date), get_next_trading_date(date)) if date not in trading_dates: raise ValueError( "expect a trading date, got {}, for reference {}".format( date.strftime("%Y%m%d"), trading_dates)) return date
def get_open_auction_info(order_book_ids, start_date=None, end_date=None, market="cn"): """获取盘前集合竞价数据 :param order_book_ids: 股票代码 :param start_date: 起始日期,默认为今天 :param end_date: 截止日期,默认为今天 :param market: (Default value = "cn") :returns: pd.DataFrame or None """ order_book_ids = ensure_order_book_ids(order_book_ids) start_date, end_date = ensure_date_range(start_date, end_date, datetime.timedelta(days=0)) history_permission_denied = realtime_permission_denied = False try: # obid add prefix 'OA_' data = get_client().execute("get_open_auction_info_daybar", ["OA_" + obid for obid in order_book_ids], start_date, end_date, OA_FIELDS + ["datetime", "date"], market=market) except PermissionDenied: data = [] history_permission_denied = True today = today_int() prev_trading_date = date_to_int8(get_previous_trading_date(today, market=market)) if data: data = [(obid[3:], {k: np.frombuffer(*v) for k, v in d.items()}) for obid, d in data] df = convert_bar_to_multi_df(data, 'datetime', OA_FIELDS + ["date"], int17_to_datetime_v, default=0.0) if df is None: history_latest_date = prev_trading_date else: history_latest_date = df["date"].max() del df["date"] else: df = None history_latest_date = prev_trading_date if history_latest_date >= end_date or start_date > today or history_latest_date >= today or end_date < today: return df try: live_df = get_today_open_auction(order_book_ids, today, market=market) except PermissionDenied: live_df = None realtime_permission_denied = True if history_permission_denied and realtime_permission_denied: raise PermissionDenied("get_open_auction_info") if live_df is None: return df if df is None: return live_df df = pd.concat([df, live_df]) df.sort_index(inplace=True) return df
def get_capital_flow_minbar(order_book_ids, start_date, end_date, fields, duration, market): history_permission_denied = realtime_permission_denied = False try: data = get_client().execute("get_capital_flow_minbar", order_book_ids, start_date, end_date, fields, duration, market=market) except PermissionDenied: history_permission_denied = True data = [] if data: data = [(obid, {k: np.frombuffer(*v) for k, v in d.items()}) for obid, d in data] df = convert_bar_to_multi_df(data, 'datetime', fields, int14_to_datetime_v) else: df = None today = today_int() if df is None: history_latest_date = date_to_int8( get_previous_trading_date(today, market=market)) else: history_latest_date = date_to_int8(df.index.get_level_values(1).max()) if history_latest_date >= end_date or start_date > today or history_latest_date >= today: return df try: live_df = get_today_capital_flow_minbar(order_book_ids, today, fields, duration, market) except PermissionDenied: live_df = None realtime_permission_denied = True if history_permission_denied and realtime_permission_denied: raise PermissionDenied("get_capital_flow_minbar") if live_df is None: return df if df is None: return live_df df = pd.concat([df, live_df]) df.sort_index(inplace=True) return df
def _weekly_start_end_date_handler(start_date, end_date): start_date = to_date(start_date) monday = start_date - datetime.timedelta(days=start_date.weekday()) first_trading_day_in_week = monday if is_trading_date(monday) else get_next_trading_date(monday) if first_trading_day_in_week < start_date: start_date = monday + datetime.timedelta(weeks=1) end_date = to_date(end_date) if end_date > datetime.date.today(): end_date = datetime.date.today() friday = end_date - datetime.timedelta(days=end_date.weekday()) + datetime.timedelta(days=4) last_trading_day_in_week = friday if is_trading_date(friday) else get_previous_trading_date(friday) if last_trading_day_in_week > end_date: end_date = friday - datetime.timedelta(weeks=1) return to_date_int(start_date), to_date_int(end_date)
def get_factor_covariance(date, horizon='daily'): """ 获取因子协方差矩阵 :param date: str 日期(例如:‘2017-03-20’) :param horizon: str 预测期限。默认为日度('daily'),可选月度(‘monthly’)或季度('quarterly')。 :return: pandas.DataFrame,其中 index 和 column 均为因子名称。 """ date = get_previous_trading_date(get_next_trading_date(date)) date = ensure_date_int(date) ensure_string_in(horizon, HORIZON_CONTAINER, 'horizon') df = get_client().execute('get_factor_covariance', date, horizon) if not df: return df = pd.DataFrame(df) df.drop("date", axis=1, inplace=True) return df.reindex(columns=df.index)
def get_margin_stocks(date=None, exchange=None, margin_type='stock', market="cn"): """获取融资融券信息 :param date: 查询日期,默认返回今天上一交易日,支持 str, timestamp, datetime 类型 :param exchange: 交易所信息,默认不填写则返回全部。 str类型,默认为 None,返回所有字段。可选字段包括: 'XSHE', 'sz' 代表深交所;'XSHG', 'sh' 代表上交所,不区分大小写 (Default value = None) :param margin_type: 'stock' 代表融券卖出,'cash',代表融资买入,默认为'stock' """ if date: date = ensure_date_int(date) else: date = get_previous_trading_date(datetime.date.today()) date = date.year * 10000 + date.month * 100 + date.day if exchange is None: exchange = EXCHANGE_CONTENT else: exchange = ensure_string(exchange, "exchange") if exchange in EXCHANGE_TYPE: exchange = EXCHANGE_TYPE[exchange] check_items_in_container(exchange, EXCHANGE_CONTENT, "exchange") exchange = [exchange] margin_type = ensure_string(margin_type, "margin_type") check_items_in_container(margin_type, MARGIN_TYPE, "margin_type") data = get_client().execute("get_margin_stocks", date, exchange, margin_type, market=market) if not data: return [] else: return sorted(data)
def jy_instrument_industry(order_book_ids, date=None, level=1, expect_df=False, market="cn"): """获取股票对应的聚源行业 :param order_book_ids: 股票列表,如['000001.XSHE', '000002.XSHE'] :param date: 如 '2015-01-07' (Default value = None) :param level: 聚源等级,0, 1, 2, 3, 'customized' (Default value = 1) :param expect_df: 返回 DataFrame,默认为 False :param market: (Default value = "cn") :returns: code, name 返回输入日期最近交易日的股票对应聚源行业以及对应的聚源等级 """ if level not in (0, 1, 2, 3, "customized"): raise ValueError("level should in 0, 1, 2, 3, 'customized'") order_book_ids = ensure_order_book_ids(order_book_ids, market=market) if not date: date = ensure_date_int( get_previous_trading_date(datetime.date.today(), market=market)) else: date = ensure_date_int(date) df = get_client().execute("jy_instrument_industry", order_book_ids, date, level, market=market) if not df: return if len(order_book_ids) == 1 and not expect_df: r = df[0] if level == 0: return r["first_industry_name"], r["second_industry_name"], r[ "third_industry_name"] return r["industry_name"] return pd.DataFrame(df).set_index("order_book_id")
def get_securities_margin(order_book_ids, start_date=None, end_date=None, fields=None, expect_df=False, market="cn"): """获取股票融资融券数据 :param order_book_ids: 股票代码或代码列表 :param start_date: 开始时间,支持 str, date, datetime, pandasTimestamp 默认为 end_date 之前一个月 (Default value = None) :param end_date: 结束时间 默认为当前日期前一天 (Default value = None) :param fields: str 或 list 类型. 默认为 None, 返回所有字段。可选字段包括: today, week, month, three_month, six_month, year, current_year, total (Default value = None) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :param market: 地区代码, 如: 'cn' (Default value = "cn") :returns: 如果传入多个股票代码,且 fields 为多个或者 None,返回 pandas.Panel 如果传入一只股票或者 fields 为单个字段,则返回 pandas.DataFrame 如果传入的股票代码和字段数都是1,则返回 pandas.Series """ order_book_ids = ensure_list_of_string(order_book_ids, "order_book_ids") all_list = [] for order_book_id in order_book_ids: if order_book_id.upper() in MARGIN_SUMMARY_MAP: all_list.append(MARGIN_SUMMARY_MAP[order_book_id.upper()]) else: inst = instruments(order_book_id, market) if inst.type in ["CS", "ETF", "LOF"]: all_list.append(inst.order_book_id) else: warnings.warn( "{} is not stock, ETF, or LOF.".format(order_book_id)) order_book_ids = all_list if not order_book_ids: raise ValueError("no valid securities in {}".format(order_book_ids)) if fields is None: fields = list(MARGIN_FIELDS) else: fields = ensure_list_of_string(fields, "fields") check_items_in_container(fields, MARGIN_FIELDS, "fields") fields = ensure_order(fields, MARGIN_FIELDS) start_date, end_date = ensure_date_range(start_date, end_date) if end_date > ensure_date_or_today_int(None): end_date = ensure_date_or_today_int( get_previous_trading_date(datetime.date.today())) trading_dates = pd.to_datetime( get_trading_dates(start_date, end_date, market=market)) data = get_client().execute("get_securities_margin", order_book_ids, start_date, end_date, market=market) if not data: return if expect_df: df = pd.DataFrame(data) df.sort_values(["order_book_id", "date"], inplace=True) df.set_index(["order_book_id", "date"], inplace=True) df = df.reindex(columns=fields) return df pl = pd.Panel(items=fields, major_axis=trading_dates, minor_axis=order_book_ids) for r in data: for field in fields: value = r.get(field) pl.at[field, r["date"], r["order_book_id"]] = value if len(order_book_ids) == 1: pl = pl.minor_xs(order_book_ids[0]) if len(fields) == 1: pl = pl[fields[0]] if len(order_book_ids) != 1 and len(fields) != 1: warnings.warn( "Panel is removed after pandas version 0.25.0." " the default value of 'expect_df' will change to True in the future." ) return pl
def _update_weekly_trading_date_index(idx): if is_trading_date(idx[1]): return idx return idx[0], get_previous_trading_date(idx[1])
def get_fundamentals(query, entry_date, interval=None, report_quarter=False, expect_df=False, market="cn"): """获取财务数据 :param query: query 对象 :param entry_date: 日期 :param interval: (Default value = None) :param report_quarter: (Default value = False) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :param market: (Default value = "cn") """ if market != "cn": raise MarketNotSupportError("don't support market {} yet.", market) if not isinstance(query, Query): raise ValueError("a sqlalchemy's Query object expected: {}".format(type(query))) raise_for_no_panel(expect_df) entry_date = to_datetime(entry_date) delta = 0 duration = 0 if interval is not None: if not isinstance(interval, str): raise ValueError( "invalid interval: {} should be a string like 1d, 5y, 3m, 2q".format(interval) ) if interval[-1] not in __TIME_DELTA_MAP__: raise ValueError( "invalid interval: {}, interval unit should be d(day), " "m(month), q(quarter) or y(year)".format(interval) ) delta = __TIME_DELTA_MAP__[interval[-1]] try: duration = int(interval[:-1]) except ValueError: raise ValueError( "invalid interval: {}, should be a string like 1d, 5y, 3m, 2q".format(interval) ) trading_dates = [get_previous_trading_date(entry_date + __TIME_DELTA_MAP__["d"], market=market)] if duration > 0: current_date = trading_dates[0] one_day = __TIME_DELTA_MAP__["d"] for i in range(duration - 1): current_date = get_previous_trading_date(current_date - delta + one_day, market=market) trading_dates.append(current_date) query = _unsafe_apply_query_filter(query, trading_dates) sql = _compile_query(query) records = get_client().execute("get_fundamentals", sql, market=market) if not records: warnings.warn("No record found") return None base_fields = ["STOCKCODE", "TRADEDATE", "RPT_YEAR", "RPT_QUARTER"] field_names = base_fields + list(set(records[0].keys()) - set(base_fields)) items = ["report_quarter"] + field_names[4:] if report_quarter else field_names[4:] if expect_df: df = pd.DataFrame(records) df.rename(columns={"STOCKCODE": "order_book_id", "TRADEDATE": "date"}, inplace=True) df["report_quarter"] = df["RPT_YEAR"].map(str) + "q" + df["RPT_QUARTER"].map(str) df.sort_values(["order_book_id", "date"], ascending=[True, False], inplace=True) df.set_index(["order_book_id", "date"], inplace=True) for item in items: if item != "report_quarter": df[item] = df[item].astype(np.float64) return df[items] # 只有一个查询日期时, 保持顺序 if len(trading_dates) > 1: stocks = list(set([r[field_names[0]] for r in records])) else: stocks = [r[field_names[0]] for r in records] stock_index = {s: i for i, s in enumerate(stocks)} day_index = {d: i for i, d in enumerate(trading_dates)} removed_items_size = 3 if report_quarter else 4 array = np.ndarray( ((len(records[0]) - removed_items_size), len(trading_dates), len(stocks)), dtype=object ) array.fill(np.nan) for r in records: istock = stock_index[r[field_names[0]]] iday = day_index[int8_to_date(r[field_names[1]])] for i in range(4, len(r)): array[(i - removed_items_size, iday, istock)] = np.float64(r[field_names[i]]) if report_quarter: array[(0, iday, istock)] = ( np.nan if None in (r[field_names[2]], r[field_names[3]]) else str(r[field_names[2]]) + "q" + str(r[field_names[3]]) ) trading_dates = pd.to_datetime(trading_dates) warnings.warn("Panel is removed after pandas version 0.25.0." "the default value of 'expect_df' will change to True in the future.") return pd.Panel(data=array, items=items, major_axis=trading_dates, minor_axis=stocks)
def get_trading_hours(order_book_id, date=None, expected_fmt="str", frequency="1m", market="cn"): """获取合约指定日期交易时间 :param order_book_id: 合约代码 :param date: 日期,默认为今天 :param expected_fmt: 返回格式,默认为str, 也支持datetime.time和datetime.datetime格式 :param frequency: 频率,默认为1m, 对应米筐分钟线时间段的起始, tick和1m相比区别在于每个交易时间段开盘往前移一分钟 :param market: (Default value = "cn") :return: trading_hours str or list of datetime.time/datetime.datetime list or None """ date = ensure_date_or_today_int(date) if not is_trading_date(date, market): warnings.warn(" %d is not a trading date" % date) return ensure_string(order_book_id, "order_book_id") ins = instruments(order_book_id) if ins is None: return ensure_string_in(expected_fmt, ("str", "time", "datetime"), "expected_fmt") ensure_string_in(frequency, ("1m", "tick"), "frequency") date_str = to_date_str(date) if ins.listed_date > date_str: return if ins.type in ( "Future", "Option" ) and ins.de_listed_date < date_str and ins.de_listed_date != "0000-00-00": return if ins.type not in ( "Future", "Option" ) and ins.de_listed_date <= date_str and ins.de_listed_date != "0000-00-00": return if ins.type == "Repo": trading_hours = "09:31-11:30,13:01-15:30" elif ins.type == "Spot": if has_night_trading(date, market): trading_hours = "20:01-02:30,09:01-15:30" else: trading_hours = "09:01-15:30" elif ins.type not in ("Future", "Option") or (ins.type == "Option" and ins.exchange in ("XSHG", "XSHE")): trading_hours = "09:31-11:30,13:01-15:00" else: trading_hours = get_client().execute("get_trading_hours", ins.underlying_symbol, date, market=market) if trading_hours is None: return # 前一天放假或者该品种上市首日没有夜盘 no_night_trading = (not has_night_trading(date, market) or get_underlying_listed_date( ins.underlying_symbol, ins.type) == date_str) if no_night_trading and not trading_hours.startswith("09"): trading_hours = trading_hours.split(",", 1)[-1] if frequency == "tick": trading_hours = ",".join([ s[:4] + str(int(s[4]) - 1) + s[5:] for s in trading_hours.split(",") ]) if expected_fmt != "str": trading_hours = [t.split("-", 1) for t in trading_hours.split(",")] for i, (start, end) in enumerate(trading_hours): trading_hours[i][0] = str_to_dt_time(start) trading_hours[i][1] = str_to_dt_time(end) if expected_fmt == "datetime": td = int8_to_date(date) prev_td = get_previous_trading_date(date) prev_td_next = prev_td + datetime.timedelta(days=1) for i, (start, end) in enumerate(trading_hours): if start.hour > 16: start_dt = prev_td end_dt = start_dt if end.hour > 16 else prev_td_next else: start_dt = end_dt = td trading_hours[i][0] = datetime.datetime.combine( start_dt, start) trading_hours[i][1] = datetime.datetime.combine(end_dt, end) return trading_hours
def get_factor(order_book_ids, factor, start_date=None, end_date=None, universe=None, expect_df=False, **kwargs): """获取因子 :param order_book_ids: 股票代码或代码列表 :param factor: 如 'total_income' :param date: 如 date='2015-01-05', 默认为前一交易日 :param start_date: 开始日期'2015-01-05', 默认为前一交易日, 最小起始日期为'2000-01-04' :param end_date: 结束日期 :param universe: 股票池,默认为全A股 :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :returns: pd.DataFrame """ order_book_ids = ensure_order_book_ids(order_book_ids, type="CS") order_book_ids = list(set(order_book_ids)) factor = ensure_list_of_string(factor) factor = list(OrderedDict.fromkeys(factor)) if start_date and end_date: start_date, end_date = ensure_date_range(start_date, end_date, datetime.timedelta(days=15)) if start_date < 20000104: warnings.warn( "start_date is earlier than 2000-01-04, adjusted to 2000-01-04" ) start_date = 20000104 elif start_date: raise ValueError("Expect end_date") elif end_date: raise ValueError("Expect start_date") else: date = kwargs.pop("date", None) date = ensure_date_int( date or get_previous_trading_date(datetime.date.today())) start_date = end_date = date if kwargs: raise ValueError('unknown kwargs: {}'.format(kwargs)) if universe is not None: universe = ensure_string(universe, "universe") if universe != "all": universe = ensure_order_book_id(universe, type="INDX") from rqdatac import index_components allowed_order_book_ids = set( index_components(universe, date=end_date) or []) not_permit_order_book_ids = [ order_book_id for order_book_id in order_book_ids if order_book_id not in allowed_order_book_ids ] if not_permit_order_book_ids: warnings.warn( "%s not in universe pool, value of those order_book_ids will always be NaN" % not_permit_order_book_ids) data = get_client().execute("get_factor_from_store", order_book_ids, factor, start_date, end_date, universe=universe) if not data: return factor_value_length = len(data[0][2]) if factor_value_length == 0: return dates = pd.to_datetime(get_trading_dates(start_date, end_date)) if len(dates) > factor_value_length: _get_factor_warning_msg(dates[factor_value_length], dates[-1]) dates = dates[0:factor_value_length] if expect_df or len(factor) > 1: order_book_id_index_map = {o: i for i, o in enumerate(order_book_ids)} factor_index_map = {f: i for i, f in enumerate(factor)} arr = np.full((len(order_book_ids) * len(dates), len(factor)), np.nan) for order_book_id, factor_name, values in data: order_book_id_index = order_book_id_index_map[order_book_id] factor_index = factor_index_map[factor_name] slice_ = slice(order_book_id_index * len(dates), (order_book_id_index + 1) * len(dates), None) arr[slice_, factor_index] = values multi_index = pd.MultiIndex.from_product( [order_book_ids, dates], names=["order_book_id", "date"]) df = pd.DataFrame(index=multi_index, columns=factor, data=arr) return df order_book_id_index_map = {o: i for i, o in enumerate(order_book_ids)} arr = np.full((len(dates), len(order_book_ids)), np.nan) for order_book_id, _, values in data: arr[:, order_book_id_index_map[order_book_id]] = values df = pd.DataFrame(index=dates, columns=order_book_ids, data=arr) if len(df.index) == 1: return df.iloc[0] if len(df.columns) == 1: return df[df.columns[0]] return df