def get_stock_connect(order_book_ids, start_date=None, end_date=None, fields=None, expect_df=False): """获取"陆股通"的持股、持股比例 :param order_book_ids: 股票列表 :param start_date: 开始日期: 如'2017-03-17' (Default value = None) :param end_date: 结束日期: 如'2018-03-16' (Default value = None) :param fields: 默认为所有字段,可输入shares_holding或者holding_ratio (Default value = None) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :returns: 返回pandas.DataFrame or pandas.Panel """ if order_book_ids not in ("shanghai_connect", "shenzhen_connect", "all_connect"): order_book_ids = ensure_order_book_ids(order_book_ids, type="CS") start_date, end_date = ensure_date_range(start_date, end_date) if fields is not None: fields = ensure_list_of_string(fields) for f in fields: if f not in ("shares_holding", "holding_ratio"): raise ValueError("invalid field: {}".format(f)) else: fields = ["shares_holding", "holding_ratio"] data = get_client().execute("get_stock_connect", order_book_ids, start_date, end_date, fields) if not data: return None df = pd.DataFrame(data, columns=["trading_date", "order_book_id"] + fields) if not expect_df and not is_panel_removed: df = df.set_index(["trading_date", "order_book_id"]) df = df.to_panel() df.major_axis.name = None df.minor_axis.name = None if len(order_book_ids) == 1: df = df.minor_xs(order_book_ids[0]) if len(fields) == 1: df = df[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 df else: df.sort_values(["order_book_id", "trading_date"], inplace=True) df.set_index(["order_book_id", "trading_date"], inplace=True) if expect_df: return df if len(order_book_ids) != 1 and len(fields) != 1: raise_for_no_panel() if len(order_book_ids) == 1: df.reset_index(level=0, drop=True, inplace=True) if len(fields) == 1: df = df[fields[0]] return df else: df = df.unstack(0)[fields[0]] df.index.name = None df.columns.name = None return df
def parse_results(records, quarters, expect_df): if not records: return None removed_items_size = 3 base_fields = ["stockcode", "rpt_year", "rpt_quarter"] field_names = base_fields + list(set(records[0].keys()) - set(base_fields)) items = field_names[removed_items_size:] if not expect_df and not is_panel_removed: # 只有一个查询日期时, 保持顺序 stocks = list(set(r[field_names[0]] for r in records)) stock_index = {s: i for i, s in enumerate(stocks)} quarter_index = {q: i for i, q in enumerate(quarters)} array = np.ndarray( (len(records[0]) - removed_items_size, len(quarters), len(stocks)), dtype=object ) array.fill(np.nan) for r in records: istock = stock_index[r[field_names[0]]] iquarter = quarter_index[(r[field_names[1]], r[field_names[2]])] for i in range(removed_items_size, len(r)): if field_names[i] == "announce_date": announce_date = r[field_names[i]] array[i - removed_items_size, iquarter, istock] = ( np.nan if announce_date is None else announce_date ) else: array[i - removed_items_size, iquarter, istock] = np.float64(r[field_names[i]]) s_quarters = ["%dq%d" % (year, quarter) for year, quarter in quarters] results = pd.Panel(data=array, items=items, major_axis=s_quarters, minor_axis=stocks) item_size, major_size, minor_size = results.shape if minor_size == 1: ret = results.minor_xs(*stocks) return ret[field_names[removed_items_size]] if item_size == 1 else ret elif item_size == 1: return results[field_names[removed_items_size]] elif major_size == 1: return results.major_xs(*s_quarters) else: 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 results else: df = pd.DataFrame(records) df.rename(columns={"stockcode": "order_book_id"}, inplace=True) df["quarter"] = df["rpt_year"].map(str) + "q" + df["rpt_quarter"].map(str) df.sort_values(["order_book_id", "quarter"], ascending=[True, False], inplace=True) df.set_index(["order_book_id", "quarter"], inplace=True) for item in items: if item != "announce_date": df[item] = df[item].astype(np.float64) df = df[items] if expect_df: return df else: if len(df.index.get_level_values(0).unique()) == 1: df.reset_index(level=0, inplace=True, drop=True) df.index.name = None df.sort_index(ascending=False, inplace=True) if len(df.columns) == 1: df = df[df.columns[0]] return df elif len(df.columns) == 1: field = df.columns[0] df = df.unstack(0)[field] df.index.name = None df.columns.name = None df.sort_index(ascending=False, inplace=True) return df elif len(df.index.get_level_values(1).unique()) == 1: df.reset_index(level=1, inplace=True, drop=True) df.index.name = None return df raise_for_no_panel()
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_price( order_book_ids, start_date=None, end_date=None, frequency="1d", fields=None, adjust_type="pre", skip_suspended=False, expect_df=False, market="cn", **kwargs ): """获取证券的历史数据 :param order_book_ids: 股票列表 :param market: 地区代码, 如 'cn' (Default value = "cn") :param start_date: 开始日期, 如 '2013-01-04' (Default value = None) :param end_date: 结束日期, 如 '2014-01-04' (Default value = None) :param frequency: 可选参数, 默认为日线。日线使用 '1d', 分钟线 '1m' (Default value = "1d") :param fields: 可选参数。默认为所有字段。 (Default value = None) :param adjust_type: 可选参数,默认为‘pre', 返回开盘价,收盘价,最高价,最低价依据get_ex_factor 复权因子(包含分红,拆分),volume依据get_split 复权因子(仅涵盖拆分)计算的前复权数据 'none'将返回原始数据 'post'返回开盘价,收盘价,最高价,最低价依据get_ex_factor 复权因子(包含分红,拆分),volume依据get_split 复权因子(仅涵盖拆分)计算的后复权数据 'pre_volume'返回开盘价,收盘价,最高价,最低价,成交量依据get_ex_factor 复权因子(包含分红,拆分)计算的前复权数据 'post_volume'返回开盘价,收盘价,最高价,最低价,成交量依据get_ex_factor 复权因子(包含分红,拆分)计算的后复权数据 'internal'返回只包含拆分的前复权数据。 (Default value = "pre") :param skip_suspended: 可选参数,默认为False;当设置为True时,返回的数据会过滤掉停牌期间, 此时order_book_ids只能设置为一只股票 (Default value = False) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :returns: 如果仅传入一只股票, 返回一个 pandas.DataFrame 如果传入多只股票, 则返回一个 pandas.Panel """ # tick数据 if frequency == "tick": return get_tick_price(order_book_ids, start_date, end_date, fields, expect_df, market) elif frequency.endswith(("d", "m", "w")): duration = int(frequency[:-1]) frequency = frequency[-1] assert 1 <= duration <= 240, "frequency should in range [1, 240]" if market == "hk" and frequency == "m" and duration not in (1, 5, 15, 30, 60): raise ValueError("frequency should be str like 1m, 5m, 15m 30m,or 60m") elif frequency == 'w' and duration not in (1,): raise ValueError("Weekly frequency should be str '1w'") else: raise ValueError("frequency should be str like 1d, 1m, 5m or tick") # 验证adjust_type if "adjusted" in kwargs: adjusted = kwargs.pop("adjusted") adjust_type = "pre" if adjusted else "none" if kwargs: raise ValueError('unknown kwargs: {}'.format(kwargs)) valid_adjust = ["pre", "post", "none", "pre_volume", "post_volume"] ensure_string(adjust_type, "adjust_type") check_items_in_container(adjust_type, valid_adjust, "adjust_type") order_book_ids = ensure_list_of_string(order_book_ids, "order_book_ids") if skip_suspended and len(order_book_ids) > 1: raise ValueError("only accept one order_book_id or symbol if skip_suspended is True") assert isinstance(skip_suspended, bool), "'skip_suspended' should be a bool" assert isinstance(expect_df, bool), "'expect_df' should be a bool" order_book_ids, stocks, funds, indexes, futures, futures888, spots, options, convertibles, repos = classify_order_book_ids( order_book_ids, market ) if not order_book_ids: warnings.warn("no valid instrument") return start_date, end_date = _ensure_date( start_date, end_date, stocks, funds, indexes, futures, spots, options, convertibles, repos ) from rqdatac.services.detail.get_price_df import get_price_df, get_week_df if frequency != 'w': df = get_price_df( order_book_ids, start_date, end_date, frequency, duration, fields, adjust_type, skip_suspended, stocks, funds, indexes, futures, futures888, spots, options, convertibles, repos, market ) if df is None or expect_df: return df # 单个合约 if len(df.index.get_level_values(0).unique()) == 1: df.reset_index(level=0, inplace=True, drop=True) # df.index.name = None if len(df.columns) == 1: df = df[df.columns[0]] return df # 单个字段 elif len(df.columns) == 1: field = df.columns[0] df = df.unstack(0)[field] # df.index.name = None df.columns.name = None return df raise_for_no_panel(False) # 交换index的顺序,以制作panel return df.swaplevel().to_panel() else: if not expect_df: raise ValueError( "Weekly frequency can only return a DataFrame object, set 'expect_df' to True to resolve this") if skip_suspended: raise ValueError( "Weekly frequency does not support skipping suspended trading days, set 'skip_suspended' to False to resolve this") start_date, end_date = _weekly_start_end_date_handler(start_date, end_date) if start_date > end_date: # 如果*当周没有结束* # 或者start date 和 end date 不能涵盖当周所有的交易日,查询该周的数据时返回为空。 return None return get_week_df(order_book_ids, start_date, end_date, fields, adjust_type, market, *(stocks, funds, indexes, futures, futures888, spots, options, convertibles, repos))
def get_turnover_rate(order_book_ids, start_date=None, end_date=None, fields=None, expect_df=False, market="cn"): """获取股票换手率数据 :param order_book_ids: 股票代码或股票代码列表 :param start_date: 开始时间 :param end_date: 结束时间;在 start_date 和 end_date 都不指定的情况下,默认为最近3个月 :param fields: str或list类型. 默认为None, 返回所有fields. field 包括: 'today', 'week', 'month', 'year', 'current_year' (Default value = None) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :param market: 地区代码, 如: 'cn' (Default value = "cn") :returns: 如果order_book_ids或fields为单个值 返回pandas.DataFrame, 否则返回pandas.Panel """ order_book_ids = ensure_order_book_ids(order_book_ids) start_date, end_date = ensure_date_range(start_date, end_date) if fields is not None: fields, mapped_fields = _get_maped_fields(fields) else: fields, mapped_fields = list(TURNOVER_FIELDS_MAP.keys()), list( TURNOVER_FIELDS_MAP.values()) df = get_client().execute("get_turnover_rate", order_book_ids, start_date, end_date, mapped_fields, market=market) df = pd.DataFrame(df, columns=["tradedate", "order_book_id"] + mapped_fields) df.rename(columns={v: k for k, v in TURNOVER_FIELDS_MAP.items()}, inplace=True) if not expect_df and not is_panel_removed: df.set_index(["tradedate", "order_book_id"], inplace=True) df.sort_index(inplace=True) df = df.to_panel() df = pf_fill_nan(df, order_book_ids) if len(order_book_ids) == 1: df = df.minor_xs(*order_book_ids) if fields and len(fields) == 1: return df[fields[0]] return df if fields and len(fields) == 1: return df[fields[0]] 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 df else: df.sort_values(["order_book_id", "tradedate"], inplace=True) df.set_index(["order_book_id", "tradedate"], inplace=True) if expect_df: return df if len(order_book_ids) != 1 and len(fields) != 1: raise_for_no_panel() if len(order_book_ids) == 1: df.reset_index(level=0, drop=True, inplace=True) if len(fields) == 1: df = df[fields[0]] return df else: df = df.unstack(0)[fields[0]] df.index.name = None df.columns.name = None return df
def get_shares(order_book_ids, start_date=None, end_date=None, fields=None, expect_df=False, market="cn"): """获取流通股本信息 :param order_book_ids: 股票名称 :param start_date: 开始日期, 如'2013-01-04' (Default value = None) :param end_date: 结束日期,如'2014-01-04' (Default value = None) :param fields: 如'total', 'circulation_a' (Default value = None) :param expect_df: 返回 MultiIndex DataFrame (Default value = False) :param market: 地区代码,如'cn' (Default value = "cn") :returns: 返回一个DataFrame """ order_book_ids = ensure_order_book_ids(order_book_ids, market=market) start_date, end_date = ensure_date_range(start_date, end_date) if fields: fields = ensure_list_of_string(fields, "fields") if 'management_circulation' in fields: fields.remove('management_circulation') if fields: warnings.warn("management_circulation is removed") else: raise ValueError("management_circulation is removed") check_items_in_container(fields, set(share_fields), "fields") fields = [share_fields[i] for i in fields] else: fields = list(share_fields.values()) all_shares = get_client().execute("get_shares", order_book_ids, fields, market=market) if not all_shares: return dates = get_trading_dates_in_type(start_date, end_date, expect_type="datetime", market=market) df = pd.DataFrame(all_shares) unique = set(df.order_book_id) for order_book_id in order_book_ids: if order_book_id not in unique: df = df.append( {"order_book_id": order_book_id, "date": df.date.iloc[-1]}, ignore_index=True ) df.set_index(["date", "order_book_id"], inplace=True) df.sort_index(inplace=True) df = df.unstack(level=1) index = df.index.union(dates) df = df.reindex(index) df = df.fillna(method="ffill") df = df.loc[list(dates)] df = df.dropna(how="all") df = df[fields] if not is_panel_removed and not expect_df: pl = df.stack(1).to_panel() pl.items = [anti_fields[i] for i in pl.items] if len(order_book_ids) == 1: pl = pl.minor_xs(order_book_ids[0]) if len(fields) == 1: pl = pl[anti_fields[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 else: df = df.stack(1) df.index.set_names(["date", "order_book_id"], inplace=True) df = df.reorder_levels(["order_book_id", "date"]).sort_index() df = df.rename(columns=anti_fields) if expect_df: return df if len(order_book_ids) != 1 and len(fields) != 1: raise_for_no_panel() if len(order_book_ids) == 1: df.reset_index(level=0, drop=True, inplace=True) if len(fields) == 1: df = df[anti_fields[fields[0]]] return df else: df = df.unstack(0)[anti_fields[fields[0]]] df.index.name = None df.columns.name = None return df
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 not expect_df and not is_panel_removed: 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 else: 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) if expect_df: return df if len(order_book_ids) != 1 and len(fields) != 1: raise_for_no_panel() if len(order_book_ids) == 1: df.reset_index(level=0, drop=True, inplace=True) if len(fields) == 1: df = df[fields[0]] return df else: df = df.unstack(0)[fields[0]] df.index.name = None df.columns.name = None return df