def cal_yoy_mom(result_list: list, store: MqQuarterStore): for i in result_list: # type: MqQuarterMetric lm = store.find_period_latest(i.ts_code, i.name, date_utils.period_delta(i.period, -1)) i.mom = cal_inc_rate(i, lm) ly = store.find_period_latest(i.ts_code, i.name, date_utils.period_delta(i.period, -4)) i.yoy = cal_inc_rate(i, ly)
def earn_in_period(quarter_store: mq_quarter_store.MqQuarterStore, ts_code: str, report_period: str, update_date: str, quarter_num: int) -> bool: period = period_delta(report_period, 1) for i in range(quarter_num): period = period_delta(period, -1) dprofit_quarter = quarter_store.find_period_latest( ts_code, mq_quarter_metric_enum.dprofit_quarter.name, period, update_date) if calculate.lt(dprofit_quarter, zero, 'value', True): return False return True
def cal_quarter_ltm(result_list: list, store: MqQuarterStore, period_o: PeriodObj, ts_code: str, update_date: str): period = period_o.end_date quarter_num = date_utils.get_quarter_num(period) report_type = period_o.report_type call_find_now = partial(store.find_period_exact, ts_code=ts_code, update_date=update_date) call_find_pre = partial(store.find_period_latest, ts_code=ts_code, update_date=update_date) call_add = partial(common_add, result_list=result_list, store=store) for k in mq_quarter_metric_enum.cal_quarter_list: name = k.name from_name = k.from_name i1 = call_find_now(period=period, name=from_name) i2 = call_find_pre(period=date_utils.period_delta(period, -1), name=from_name) quarter = quarter_cal_utils.cal_quarter(name, i1, i2) if quarter is None: common_log_err(ts_code, period, report_type, update_date, name) else: call_add(to_add=quarter) for k in mq_quarter_metric_enum.cal_ltm_list: name = k.name from_name = k.from_name i1 = call_find_now(period=period, name=from_name) i2 = call_find_pre(period=date_utils.period_delta(period, -1), name=from_name) i3 = call_find_pre(period=date_utils.period_delta(period, -2), name=from_name) i4 = call_find_pre(period=date_utils.period_delta(period, -3), name=from_name) ltm: MqQuarterMetric = quarter_cal_utils.cal_ltm_with_quarter( name, i1, i2, i3, i4) if ltm is None and quarter_num == 4: q_m: MqQuarterMetricEnum = mq_quarter_metric_enum.find_by_name( from_name) ltm = quarter_cal_utils.add_up( name, [call_find_now(period=period, name=q_m.from_name)]) if ltm is None: common_log_err(ts_code, period, report_type, update_date, name) else: call_add(to_add=ltm)
def extract_from_cash_flow(result_list: list, store: MqQuarterStore, period_dict: dict, cf: TsCashFlow): update_date = date_utils.format_delta(cf.mq_ann_date, -1) ts_code = cf.ts_code period = cf.end_date call_find = partial(store.find_period_exact, ts_code=ts_code, period=period, update_date=update_date) call_add_nx = partial(add_nx, ts_code=ts_code, period=period, update_date=update_date, report_type=mq_report_type.report if cf.report_type == '1' else mq_report_type.report_adjust, store=store, result_list=result_list, period_dict=period_dict) for i in mq_quarter_metric_enum.extract_from_cf_list: if i.is_cf_h and date_utils.get_quarter_num(cf.end_date) == 3: q2: MqManualMetric = store.find_period_latest( ts_code=cf.ts_code, name=i.name, period=date_utils.period_delta(cf.end_date, -1), update_date=update_date) if q2 is None: log.error('Cant find q2 in cash flow %s %s %s' % (cf.ts_code, cf.end_date, cf.mq_ann_date)) call_add_nx(name=i.name, value=getattr(cf, i.from_name)) else: call_add_nx(name=i.name, value=q2.value) else: call_add_nx(name=i.name, value=getattr(cf, i.from_name))
def fetch_from_period(): s: Session = db_client.get_session() result = s.query(func.max(TsCashFlow.end_date)) \ .all() s.close() from_date = fetch_data_start_period if len(result) > 0 and not result[0][0] is None: from_date = date_utils.period_delta(result[0][0], -4) return from_date
def fetch_by_period(to_date: str = date_utils.get_current_dt()): to_period = date_utils.period_delta(date_utils.next_period(to_date), 1) # 年报和一季度的预报可能同时出 from_period = fetch_from_period() return fetch.common_fetch_report_by_period(TsForecast, 'fetch_forecast', TsForecast.end_date, from_period=from_period, to_period=to_period)
def cal_complex_quarter_ltm(result_list: list, store: MqQuarterStore, period_o: PeriodObj, ts_code: str, update_date: str): ''' 计算复杂指标的单季和ltm, 在所有复杂指标计算后 暂无 ''' period = period_o.end_date report_type = period_o.report_type call_find_now = partial(store.find_period_exact, ts_code=ts_code, update_date=update_date) call_find_pre = partial(store.find_period_latest, ts_code=ts_code, update_date=update_date) call_add = partial(common_add, result_list=result_list, store=store) for k in mq_quarter_metric_enum.complex_quarter_list: name = k.name from_name = k.from_name current = call_find_now(period=period, name=from_name) lp = call_find_pre(period=date_utils.period_delta(period, -1), name=from_name) quarter = quarter_cal_utils.cal_quarter(name, current, lp) if quarter is None: common_log_err(ts_code, period, report_type, update_date, name) else: call_add(to_add=quarter) for k in mq_quarter_metric_enum.complex_ltm_list: name = k.name from_name = k.from_name current = call_find_now(period=period, name=from_name) last_year_q4 = call_find_pre(period=date_utils.q4_last_year(period), name=from_name) last_year = call_find_pre(period=date_utils.period_delta(period, -4), name=from_name) ltm = quarter_cal_utils.cal_ltm_with_period(name, current, last_year_q4, last_year) if ltm is None: common_log_err(ts_code, period, report_type, update_date, name) else: call_add(to_add=ltm)
def earn_and_dividend_in_year(quarter_store: mq_quarter_store.MqQuarterStore, ts_code: str, report_period: str, update_date: str, year: int) -> bool: quarter_num = get_quarter_num(report_period) period = report_period if quarter_num == 4 else period_delta( report_period, -quarter_num) period = period_delta(period, 4) for i in range(year): period = period_delta(period, -4) dprofit_ltm = quarter_store.find_period_latest( ts_code, mq_quarter_metric_enum.dprofit_ltm.name, period, update_date) dividend_ltm = quarter_store.find_period_latest( ts_code, mq_quarter_metric_enum.dividend_ltm.name, period, update_date) if calculate.lt(dprofit_ltm, zero, 'value', True): return False if calculate.lt(dividend_ltm, zero, 'value', True): return False return True
def history_dividend_yoy_score(quarter_store: mq_quarter_store.MqQuarterStore, ts_code: str, report_period: str, update_date: str, year: int) -> bool: quarter_num = get_quarter_num(report_period) period = report_period if quarter_num == 4 else period_delta( report_period, -quarter_num) period = period_delta(period, 4) yoy_list = [] for i in range(year): period = period_delta(period, -4) dividend_ltm = quarter_store.find_period_latest( ts_code, mq_quarter_metric_enum.dividend_ltm.name, period, update_date) yoy_list.append(calculate.get_val(dividend_ltm, 'yoy', zero)) result = 0 score_per_one = 100 / year for yoy in yoy_list: if yoy > 0: result += score_per_one elif yoy < 0: result -= score_per_one / 2 return decimal_utils.valid_score(result)
def cal_avg(result_list: list, store: MqQuarterStore, period_o: PeriodObj, ts_code: str, update_date: str): period = period_o.end_date report_type = period_o.report_type call_find_now = partial(store.find_period_exact, ts_code=ts_code, update_date=update_date) call_find_pre = partial(store.find_period_latest, ts_code=ts_code) call_add = partial(common_add, result_list=result_list, store=store) for k in mq_quarter_metric_enum.cal_avg_list: from_name = k.from_name i1 = call_find_now(period=period, name=from_name) i2 = call_find_pre(period=date_utils.period_delta(period, -1), name=from_name) i3 = call_find_pre(period=date_utils.period_delta(period, -2), name=from_name) i4 = call_find_pre(period=date_utils.period_delta(period, -3), name=from_name) avg = quarter_cal_utils.cal_ltm_avg(k.name, i1, i2, i3, i4) if avg is None: common_log_err(ts_code, period, report_type, update_date, k.name) else: call_add(to_add=avg)
def cal(daily_store: mq_daily_store.MqDailyStore, quarter_store: mq_quarter_store.MqQuarterStore, ts_code: str, update_date: str) -> MqDailyMetric: score = 0 peg = 0 report_type = 0 period = '00000000' pe: MqDailyMetric = daily_store.find_date_exact(ts_code, mq_daily_metric_enum.pe.name, update_date) dprofit_quarter = quarter_store.find_latest(ts_code, mq_quarter_metric_enum.dprofit_quarter.name, update_date) dprofit_quarter_ly = quarter_store.find_period_latest( ts_code, mq_quarter_metric_enum.dprofit_quarter.name, period=date_utils.period_delta(dprofit_quarter.period, -1), update_date=update_date) if dprofit_quarter is not None else None dprofit_ltm = quarter_store.find_latest(ts_code, mq_quarter_metric_enum.dprofit_ltm.name, update_date) if pe is None or dprofit_quarter is None or dprofit_quarter_ly is None or dprofit_ltm is None: score = -1 elif calculate.gt(pe, max_pe, field='value') or calculate.lt(pe, zero, field='value'): score = -1 elif calculate.lt(dprofit_quarter, zero, field='value') or calculate.lt(dprofit_quarter, min_yoy, field='yoy'): score = -1 elif calculate.lt(dprofit_quarter_ly, min_dprofit, field='value'): score = -1 elif calculate.lt(dprofit_ltm, zero, field='value') or \ calculate.lt(decimal_utils.div(dprofit_quarter.value, dprofit_ltm.value), min_dprofit_percent): score = -1 else: peg = decimal_utils.div(decimal_utils.div(pe.value, dprofit_quarter.yoy), 100) report_type = pe.report_type | dprofit_quarter.report_type period = max(pe.period, dprofit_quarter.period) if peg > max_peg: score = -1 else: score = (1 - peg / max_peg) * 100 peg_metric = MqDailyMetric(ts_code=ts_code, report_type=report_type, period=period, update_date=update_date, name=mq_daily_metric_enum.peg.name, value=peg) grow_score_metric = MqDailyMetric(ts_code=ts_code, report_type=report_type, period=period, update_date=update_date, name=mq_daily_metric_enum.grow_score.name, value=valid_score(score)) return [peg_metric, grow_score_metric]
def generate_report_message_by_code( ts_code: str, share_name: str, to_date: str = date_utils.get_current_dt()): result_list = [] from_date = mq_calculate_start_date session = db_client.get_session() last_one: MqMessage = session.query(MqMessage) \ .filter(MqMessage.ts_code == ts_code, MqMessage.msg_type <= 3) \ .order_by(MqMessage.pub_date.desc()).limit(1).all() if len(last_one) > 0: from_date = date_utils.format_delta(last_one[0].pub_date, 1) quarter_store = mq_quarter_store.init_quarter_store_by_date( ts_code, from_date) session.close() while from_date <= to_date: # type: MqQuarterBasic latest = quarter_store.find_latest(ts_code, mq_quarter_metric_enum.dprofit.name, from_date) if latest is None: from_date = date_utils.format_delta(from_date, 1) continue for i in range(5): period = date_utils.period_delta(latest.period, -i) dprofit = quarter_store.find_period_exact( ts_code, mq_quarter_metric_enum.dprofit.name, period, from_date) if dprofit is None: continue # 只保留官方财报 if not ((dprofit.report_type & (1 << mq_report_type.report)) > 0 or \ (dprofit.report_type & (1 << mq_report_type.forecast)) > 0 or \ (dprofit.report_type & (1 << mq_report_type.express)) > 0): continue result_list.append( MqMessage(ts_code=ts_code, msg_type=mq_message_type.report, message=get_report_message_content( dprofit, share_name), pub_date=date_utils.format_delta(from_date, 1))) from_date = date_utils.format_delta(from_date, 1) return result_list
def cal_fcf(result_list: list, store: MqQuarterStore, period_o: PeriodObj, ts_code: str, update_date: str): ''' 计算自由现金流,依赖于 cal_rev_pay, cal_quarter_ltm ''' period = period_o.end_date report_type = period_o.report_type call_find = partial(store.find_period_exact, ts_code=ts_code, period=period, update_date=update_date) call_find_ly = partial(store.find_period_latest, ts_code=ts_code, period=date_utils.q4_last_year(period)) call_find_lp = partial(store.find_period_latest, ts_code=ts_code, period=date_utils.period_delta(period, -1)) call_add = partial(common_add, result_list=result_list, store=store) call_log = partial(common_log_err, ts_code=ts_code, period=period, update_date=update_date, report_type=report_type) if mq_report_type.is_report(report_type): total_receivable_delta = common_cal_delta(call_find, call_find_ly, 'total_receivable') prepayment_delta = common_cal_delta(call_find, call_find_ly, 'prepayment') # 经营性应收项目增加 = 应收账款增加 + 预付账款增加 + 应收票据增加 op_recv_delta = quarter_cal_utils.add_up( 'op_recv_delta', [total_receivable_delta, prepayment_delta]) total_payable_delta = common_cal_delta(call_find, call_find_ly, 'total_payable') adv_receipts_delta = common_cal_delta(call_find, call_find_ly, 'adv_receipts') # 经营性应付项目增加 = 应付账款增加 + 预收账款增加 + 应付票据增加 op_pay_delta = quarter_cal_utils.add_up( 'op_pay_delta', [total_payable_delta, adv_receipts_delta]) inventories_delta = common_cal_delta(call_find, call_find_ly, 'inventories') lt_amor_exp_delta = common_cal_delta(call_find, call_find_ly, 'lt_amor_exp') # 营运资本增加 = 存货增加 + 经营性应收项目增加 + 长期待摊费用增加 - 经营性应付项目增加 - 预提费用增加 (已经取消) op_cap_delta = quarter_cal_utils.sub_from('op_cap_delta', [ quarter_cal_utils.add_up( '_', [inventories_delta, op_recv_delta, lt_amor_exp_delta]), op_pay_delta ]) prov_depr_assets = call_find(name='prov_depr_assets') depr_fa_coga_dpba = call_find(name='depr_fa_coga_dpba') amort_intang_assets = call_find(name='amort_intang_assets') lt_amort_deferred_exp = call_find(name='lt_amort_deferred_exp') loss_scr_fa = call_find(name='loss_scr_fa') # 折旧与摊销 = 资产减值准备 + 固定资产折旧 + 无形资产摊销 + 长期待摊费用摊销 + 固定资产报废损失 daa = quarter_cal_utils.add_up('daa', [ prov_depr_assets, depr_fa_coga_dpba, amort_intang_assets, lt_amort_deferred_exp, loss_scr_fa ]) # 资本支出 = 非流动性资产增加 - 可供出售金融资产增加 total_nca_delta = common_cal_delta(call_find, call_find_ly, 'total_nca') fa_avail_for_sale_delta = common_cal_delta(call_find, call_find_ly, 'fa_avail_for_sale') fa_avail_for_sale_delta = None # 取消了 cap_cost = quarter_cal_utils.sub_from( 'cap_cost', [total_nca_delta, fa_avail_for_sale_delta]) dprofit = call_find(name='dprofit') # 自由现金流 = 归母扣非净利 + 折旧与摊销 - 营运资本增加 - 资本支出 fcf = quarter_cal_utils.sub_from('fcf', [ quarter_cal_utils.add_up('_', [dprofit, daa]), op_cap_delta, cap_cost ]) else: dprofit_ltm_lp = call_find_lp(name='dprofit_ltm') fcf_ltm_lp = call_find_lp(name='fcf_ltm') dprofit = call_find(name='dprofit') fcf = quarter_cal_utils.multiply( dprofit, quarter_cal_utils.dividend(fcf_ltm_lp, dprofit_ltm_lp, '_'), 'fcf') if fcf is None or fcf.period != period: call_log(name='fcf') else: call_add(to_add=fcf)