def st(): db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) st_df = pd.read_csv(config.get("files").get("st"), header=0) st_df['ticker'] = st_df['ticker'].map(lambda x: str(x).zfill(6)) for index, row in st_df.iterrows(): _date = str(row["tradeDate"]).replace('-', '') _market = 0 if str(row["exchangeCD"]) == "XSHG": _market = 1 db_client.upsert_one(_filter={ "code": str(row["ticker"]), "market": _market, "date": _date }, _value={ "st": 1, "name": "%s" % row['tradeAbbrName'] }, _upsert=False) print("更新记录: %d" % index)
def plot1(years, money): tax = 0.00025 # 买卖按照万分之2.5计算 for item in config.get("indexes"): _market = item[0] _idx_code = item[1] _money_per = money click.echo("开始计算 %d - %s 指数的回测策略" % (_market, _idx_code)) _start_date = date.datetime_to_str(date.years_ago(years)) last_day_list = date.last_days(int(_start_date), 1, True) # 每月最后一个交易日集合 data = [] db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) _idx_list = db_client.find_stock_list(_filter={ "code": _idx_code, "market": _market }, _sort=[("date", pymongo.ASCENDING)], _fields={ "date": 1, "close": 1 }) item_df = pd.DataFrame(list(_idx_list), columns=["date", "close"]) item_df = item_df.dropna(0) total_count = int(0) # 累计数量 for idx, item_date in enumerate(last_day_list): last_df = item_df[item_df["date"] == str(item_date)] if last_df is None or len(last_df) <= 0: continue item_point = last_df.ix[last_df.index.values[0]]["close"] item_count = _money_per * (1 - tax) / item_point total_count += item_count data.append([item_date, "买入", item_point, item_count, total_count]) item = data.pop(-1) item_count = total_count * item[2] * (1 - tax) / item[2] data.append([item[0], "卖出", item[2], item_count, 0]) result_df = pd.DataFrame(data, columns=["日期", "操作", "单价", "数量", "累计数量"]) result_df.to_csv(config.get("files").get("plots") % (PROJECT_ROOT, "plot1", _market, _idx_code), index=False, mode="w", header=True, encoding='gb18030', float_format="%.3f")
def _indexes(idx_market, idx_code, start_date, calendar_df): db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) today = int("".join(time.strftime('%Y%m%d', time.localtime(time.time())))) item_last = db_client.find_stock_item(_filter={ "code": idx_code, "market": idx_market, "dr": { "$exists": True } }, _sort=[("date", pymongo.DESCENDING)]) if item_last is not None and len(item_last) > 0: calendar_df = calendar_df[ calendar_df["calendarDate"] > int(item_last.get("date"))] click.echo("\t开始 %s 指数的估值信息..." % idx_code) for _, row in calendar_df.iterrows(): cal_date = int(row["calendarDate"]) if row['isOpen'] == 0 or cal_date < start_date or cal_date > today: continue click.echo("\t\t计算%d-%s - %d ..." % (idx_market, idx_code, cal_date)) _result = index.index_val(cal_date, idx_code, db_client) if _result is not None: click.echo("\t\t\t code:%s, pe_ttm:%s, pb:%s" % (idx_code, _result[0], _result[1])) db_client.upsert_one(_filter={ "code": str(idx_code), "market": idx_market, "date": str(cal_date) }, _value={ "pe_ttm": _result[0], "pb": _result[1], "roe": _result[2], "dr": _result[3] }) click.echo("\t%s 指数的估值信息计算完毕" % idx_code)
def a(): """计算A股PE中值""" click.echo("开始计算整个A股的估值信息...") first = True result_list = [] db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) calendar_df = pd.read_csv(config.get("files").get("calendar"), header=0) today = int("".join(time.strftime('%Y%m%d', time.localtime(time.time())))) try: stock_df = pd.read_csv(config.get("files").get("stock_a"), header=0, encoding="utf8") if len(stock_df) > 0: first = False item_last = stock_df.loc[stock_df.index[-1]] calendar_df = calendar_df[ calendar_df["calendarDate"] > int(item_last["date"])] except FileNotFoundError: pass for _, row in calendar_df.iterrows(): cal_date = int(row["calendarDate"]) if row['isOpen'] == 0 or 20020328 > cal_date or cal_date > today: continue stock_day_list = db_client.find_stock_list(_filter={ "date": str(cal_date), "fixed": { "$exists": True } }, _sort=[("code", pymongo.ASCENDING)], _fields={ "market": 1, "code": 1, "close": 1, "pe_ttm": 1, "pb": 1, "roe": 1, "dr": 1 }) stock_df = pd.DataFrame( stock_day_list, columns=['market', 'code', 'close', 'pe_ttm', 'pb', 'roe', 'dr']) stock_df = stock_df.fillna(0) pe_list = [] pb_list = [] roe_list = [] dr_list = [] for _, r in stock_df.iterrows(): pe_list.append(r['pe_ttm']) pb_list.append(r['pb']) roe_list.append(r['roe']) dr_list.append(r['dr']) mid_value_pe = number.get_median(pe_list) mid_value_pb = number.get_median(pb_list) avg_value_roe = number.get_average(roe_list) avg_value_dr = number.get_average(dr_list) click.echo("计算 %s 日的数据中值, pe=%f, pb=%f, roe=%f, dr=%f ... " % (cal_date, mid_value_pe, mid_value_pb, avg_value_roe, avg_value_dr)) result_list.append([ cal_date, mid_value_pe, mid_value_pb, avg_value_roe, avg_value_dr ]) if len(result_list) % 50 == 0: if first: first = False result_df = pd.DataFrame( result_list, columns=['date', 'pe', 'pb', 'roe', 'dr']) result_df.to_csv(config.get("files").get("stock_a"), index=False, mode="w", header=True, encoding='utf8', float_format="%.6f") else: result_df = pd.DataFrame( result_list, columns=['date', 'pe', 'pb', 'roe', 'dr']) result_df.to_csv(config.get("files").get("stock_a"), index=False, mode="a+", header=False, encoding='utf8', float_format="%.6f") result_list = [] result_df = pd.DataFrame(result_list, columns=['date', 'pe', 'pb', 'roe', 'dr']) result_df.to_csv(config.get("files").get("stock_a"), index=False, mode="a+", header=False, encoding='utf8', float_format="%.6f") click.echo("整个A股的估值信息计算完毕...")
def plot2(years, money): """ 红利指数定投进阶方案 80% <= pe百分位: 全卖 60% <= pe百分位 < 80%: 定赎回 40% <= pe百分位 < 60%: 正常定投 20% <= pe百分位 < 40%: 1.5倍定投 pe百分位 < 20%: 2倍定投 :return: """ tax = 0.00025 # 买卖按照万分之2.5计算 for item in config.get("indexes"): data = [] _market = item[0] _idx_code = item[1] _money_per = money click.echo("开始计算 %d - %s 指数的回测策略" % (_market, _idx_code)) _start_date = date.datetime_to_str(date.years_ago(years)) last_day_list = date.last_days(int(_start_date), 1, True) # 每月最后一个交易日集合 db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) _idx_list = db_client.find_stock_list(_filter={ "code": _idx_code, "market": _market }, _sort=[("date", pymongo.ASCENDING)], _fields={ "date": 1, "pe_ttm": 1, "close": 1 }) item_df = pd.DataFrame(list(_idx_list), columns=["date", "pe_ttm", "close"]) item_df = item_df.dropna(0) _pe_series = 1 / item_df["pe_ttm"] item_df.insert(0, 'rank', _pe_series.rank(pct=True)) item_df = item_df.reset_index() total_count = 0 # 累计数量 for idx, item_date in enumerate(last_day_list): last_df = item_df[item_df["date"] == str(item_date)] if last_df is None or len(last_df) <= 0: continue _tmp_rank = last_df.ix[last_df.index.values[0]]["rank"] item_point = last_df.ix[last_df.index.values[0]]["close"] item_rank = float("%.2f" % ((1 - _tmp_rank) * 100)) if item_rank >= 80 and total_count > 0: # 全部卖出, 卖出后要扣税费 item_count = total_count * item_point * (1 - tax) / item_point data.append( [item_date, item_rank, "卖出", -item_point, item_count, 0]) total_count = 0 elif 60 <= item_rank < 80: # 卖出1份 _op = "卖出" # 卖出的这一份应该包含税费,所以要多卖出一部分税费的数量 item_count = _money_per * (1 + tax) / item_point if total_count >= item_count: total_count -= item_count elif total_count > 0: item_count = total_count total_count = 0 else: _op = "/" item_count = 0 total_count = 0 data.append([ item_date, item_rank, _op, -item_point, item_count, total_count ]) elif 40 <= item_rank < 60: # 买入1份 item_count = _money_per * (1 - tax) / item_point total_count += item_count data.append([ item_date, item_rank, "买入", item_point, item_count, total_count ]) elif 20 <= item_rank < 40: # 买入1.5份 item_count = (_money_per * 1.5) * (1 - tax) / item_point total_count += item_count data.append([ item_date, item_rank, "买入", item_point, item_count, total_count ]) elif 0 <= item_rank < 20: # 买入2份 item_count = (_money_per * 2) * (1 - tax) / item_point total_count += item_count data.append([ item_date, item_rank, "买入", item_point, item_count, total_count ]) else: data.append( [item_date, item_rank, "/", item_point, 0, total_count]) result_df = pd.DataFrame( data, columns=["日期", "百分位", "操作", "单价", "数量", "累计数量"]) result_df.to_csv(config.get("files").get("plots") % (PROJECT_ROOT, "plot2", _market, _idx_code), index=False, mode="w", header=True, encoding='gb18030', float_format="%.3f")
def mv(): """ 总市值=当前股价×总股本 """ click.echo("计算总股本、流通股本、流通市值、总市值、股息率...") db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) base_df = stocks.stock_a_list() bonus_df = bonus.bonus_with(None) report_df = pd.read_csv(config.get("files").get("reports"), header=0, encoding="utf8") report_df['code'] = report_df['code'].map(lambda x: str(x).zfill(6)) for index, row in base_df.iterrows(): try: print("计算 %d-%s 的股本、市值、股息率" % (row["market"], row["code"])) ccs = 0 # 流通股 tcs = 0 # 总股本 stock_day_list = db_client.find_stock_list(_filter={ "code": row['code'], "market": row["market"], "close": { "$exists": True } }, _sort=[ ("date", pymongo.ASCENDING) ], _fields={ "date": 1, "close": 1 }) if len(stock_day_list) <= 0: # 股票本身没有交易量 continue stock_day_df = pd.DataFrame(stock_day_list, columns=['date', 'close']) try: item_last = db_client.find_stock_item(_filter={ "code": row['code'], "market": row["market"], "dr": { "$exists": True } }, _sort=[ ("date", pymongo.DESCENDING) ]) if item_last is not None and len(item_last) > 0: # 如果之前计算过,则无需重头计算 last_day_df = stock_day_df[stock_day_df["date"] == item_last['date']] stock_day_df = stock_day_df[ stock_day_df.index > last_day_df.index.values[0]] ccs = item_last["cmv"] // item_last["close"] # 流通股 tcs = item_last["tmv"] // item_last["close"] # 总股本 except FileNotFoundError: pass filter_bonus_df = bonus_df[(bonus_df["code"] == row["code"]) & (bonus_df["type"] != 6) & ((bonus_df["type"] > 1) & (bonus_df["type"] < 13))] filter_bonus_df = filter_bonus_df.sort_values(['date'], ascending=True) filter_report_df = report_df[report_df["code"] == row["code"]] filter_report_df = filter_report_df.sort_values(['date'], ascending=True) for idx, item in stock_day_df.iterrows(): item_df = filter_bonus_df[filter_bonus_df["date"] == int( item["date"])] if len(item_df) > 0: # 高送转中记录的数据单位都到万 ccs = item_df.ix[item_df.index.values[0]]["count"] * 10000 tcs = item_df.ix[item_df.index.values[0]]["rate"] * 10000 item_df = filter_report_df[filter_report_df["publish"] == int( item["date"])] if len(item_df) > 0: ccs = item_df.ix[item_df.index.values[0]]["ccs"] tcs = item_df.ix[item_df.index.values[0]]["tcs"] ccs_mv = item["close"] * ccs tcs_mv = item["close"] * tcs # 3年的股息率 dr = bonus.dividend_rate_with(int(item["date"]), row["code"], item["close"]) db_client.upsert_one(_filter={ "code": str(row["code"]), "market": row["market"], "date": str(item["date"]) }, _value={ "cmv": ccs_mv, "tmv": tcs_mv, "dr": dr }) except FileNotFoundError: continue click.echo("总股本、流通股本、流通市值、总市值、股息率 计算完毕...")
def pe_pb_roe(): """ 转换PE、PB、ROE、股息率 四个指标需要的信息 1.基本每股收益、4.每股净资产、96.归属于母公司所有者的净利润、238.总股本、239.已上市流通A股 PE=股价/每股收益 PB=股价/每股净资产 ROE=利润/每股净资产=PB/PE : 财报中已有静态的净资产收益率数据, 这里通过TTM计算一个大概的ROE作为参考 :return: """ db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) base_df = stocks.stock_a_list() for index, row in base_df.iterrows(): try: print("计算 %d-%s 的PE、PB、ROE数据..." % (row["market"], row["code"])) stock_day_list = db_client.find_stock_list(_filter={ "code": row['code'], "market": row["market"], "close": { "$exists": True } }, _sort=[ ("date", pymongo.ASCENDING) ], _fields={ "date": 1, "close": 1 }) if len(stock_day_list) <= 0: # 股票本身没有交易量 continue stock_day_df = pd.DataFrame(stock_day_list, columns=['date', 'close']) item_last = db_client.find_stock_item(_filter={ "code": row['code'], "market": row["market"], "pb": { "$exists": True } }, _sort=[("date", pymongo.DESCENDING)]) if item_last is not None and len(item_last) > 0: # 如果之前计算过,则无需重头计算 last_day_df = stock_day_df[stock_day_df["date"] == item_last['date']] stock_day_df = stock_day_df[ stock_day_df.index > last_day_df.index.values[0]] for idx, item in stock_day_df.iterrows(): lyr_value = rt.lyr_with(int(item["date"]), row['code'], item["close"]) pe_value = rt.ttm_with(int(item["date"]), row['code'], item["close"]) pb_value = rt.pb_with(int(item["date"]), row['code'], item["close"]) roe_value = 0.0 if pe_value != 0.0: roe_value = pb_value / pe_value db_client.upsert_one(_filter={ "code": str(row["code"]), "market": row["market"], "date": str(item["date"]) }, _value={ "lyr": lyr_value, "pe_ttm": pe_value, "pb": pb_value, "roe": roe_value }) except FileNotFoundError: continue
def fixed(): db_client = MongoDBClient( config.get("db").get("mongodb"), config.get("db").get("database")) base_df = stocks.stock_a_list() bonus_df = bonus.bonus_with(None) for index, row in base_df.iterrows(): try: prev_close = 0 prev_fixed_close = 0 print("计算 %d-%s 的后复权数据" % (row["market"], row["code"])) stock_day_list = db_client.find_stock_list(_filter={ "code": row['code'], "market": row["market"] }, _sort=[ ("date", pymongo.ASCENDING) ], _fields={ "date": 1, "close": 1 }) if len(stock_day_list) <= 0: # 股票本身没有交易量无需复权 continue stock_day_df = pd.DataFrame(stock_day_list, columns=['date', 'close']) try: item_last = db_client.find_stock_item(_filter={ "code": row['code'], "market": row["market"], "fixed": { "$exists": True } }, _sort=[ ("date", pymongo.DESCENDING) ]) if item_last is not None and len(item_last) > 0: # 如果之前计算过后复权价,则无需重头计算 last_day_df = stock_day_df[stock_day_df["date"] == item_last['date']] prev_close = last_day_df.ix[ last_day_df.index.values[0]]["close"] prev_fixed_close = item_last["fixed"] stock_day_df = stock_day_df[ stock_day_df.index > last_day_df.index.values[0]] except FileNotFoundError: # 如果从来没计算过后复权价则不管 pass filter_df = bonus_df[(bonus_df["type"] == 1) & (bonus_df["code"] == row["code"])] filter_df = filter_df.sort_values(['date'], ascending=True) for idx, item in stock_day_df.iterrows(): money = 0 # 分红 count = 0 # 送股数 item_df = filter_df[filter_df["date"] == int(item["date"])] if len(item_df) > 0: money = item_df.ix[item_df.index.values[0]]["money"] / 10 count = item_df.ix[item_df.index.values[0]]["count"] / 10 # 除息除权日当天复权后的涨幅 =(当天不复权收盘价 *(1 + 每股送股数量)+每股分红金额) / 上一个交易日的不复权收盘价 # 复权收盘价 = 上一个交易日的复权收盘价 *(1 + 复权涨幅) if prev_close > 0: daily_rate_close = (item["close"] * (1 + count) + money) / prev_close prev_fixed_close = prev_fixed_close * daily_rate_close else: prev_fixed_close = item["close"] prev_close = item["close"] db_client.upsert_one(_filter={ "code": str(row["code"]), "market": row["market"], "date": str(item["date"]) }, _value={"fixed": prev_fixed_close}) except FileNotFoundError: continue