Exemplo n.º 1
0
def common_fetch(exchange: str, to_date: str = date_utils.get_current_dt()):
    """
    按交易所获取交易日历
    :param exchange: SSE上交所,SZSE深交所
    :param to_date: 获取截止日期
    :return:
    """
    from_date = fetch_from_date(exchange)
    while from_date <= to_date:
        next_date = date_utils.format_delta(from_date, 1000)
        if next_date > to_date:
            next_date = to_date
        for cnt in range(2):
            log.info('To fetch trade calendar %s %s~%s' %
                     (exchange, from_date, next_date))
            try:
                df: DataFrame = ts_client.fetch_trade_cal(exchange=exchange,
                                                          start_date=from_date,
                                                          end_date=next_date)
                if not df.empty:
                    db_client.store_dataframe(df, TsTradeCal.__tablename__)
                    log.info('Successfully save trade cal: %s~%s' %
                             (from_date, to_date))
                break
            except Exception as e:
                log.exception(
                    'Calling TuShare too fast. Will sleep 1 minutes...',
                    exc_info=e)
                time.sleep(60)
                ts_client.init_token()
        from_date = date_utils.format_delta(next_date, 1)
Exemplo n.º 2
0
def common_fetch_data(ts_code: str,
                      api_name: str,
                      table: Table,
                      date_field: str,
                      code_field: str,
                      to_date: str = date_utils.get_current_dt(),
                      to_do: bool = True,
                      page_size: int = 1000):
    """
    :param ts_code: 股票编码
    :param api_name: 调用tsclient的方法名
    :param table: sqlalchemy的表定义
    :param date_field: 对应发布日期的字段名 用于获取该类型数据在DB中最新日期
    :param code_field: 对应股票编码的字段名
    :param to_date: 数据要获取到哪天
    :param to_do: 是否要进行此次获取
    :param page_size: 每次获取多少条数据
    :return:
    """
    if not to_do:
        return False, None
    # 财报的 end_date 是第二天,不过目前是没有那么快有数据的
    to_date = trade_date_service.get_next_trade_date(to_date)
    from_date = fetch_from_date(date_field, code_field, ts_code)
    from_date_to_ret = None
    while from_date < to_date:
        stock_data = None
        next_date = date_utils.format_delta(from_date, page_size)
        if next_date >= to_date:
            next_date = to_date
        for cnt in range(2):
            log.info('To fetch %s of stock %s %s~%s' %
                     (table.__tablename__, ts_code, from_date, next_date))
            try:
                param = {
                    'ts_code': ts_code,
                    'start_date': from_date,
                    'end_date': next_date
                }
                stock_data = ts_client.fetch_data_frame(api_name, **param)
                break
            except Exception as e:
                log.exception(
                    'Calling TuShare too fast. Will sleep 1 minutes...',
                    exc_info=e)
                time.sleep(60)
                ts_client.init_token()

        if stock_data is not None and not stock_data.empty:
            db_client.store_dataframe(stock_data, table.__tablename__)
            if from_date_to_ret is None:
                from_date_to_ret = from_date
            log.info('Successfully save %s of stock %s %s~%s' %
                     (table.__tablename__, ts_code, from_date, next_date))

        from_date = date_utils.format_delta(next_date, 1)

    return True, from_date_to_ret
Exemplo n.º 3
0
def get_period_open_close(ts_code_list, from_date, to_date):
    sql = """
        select
            ori.*
        from
        (
            select
                *
            from mq_daily_price
                where is_trade = 1
                and trade_date between '%s' and '%s'
                and ts_code in (%s)
        ) ori
        left join
        (
            select
                ts_code,
                max(trade_date) as max_dt,
                min(trade_date) as min_dt
            from mq_daily_price
            where is_trade = 1
            and trade_date between '%s' and '%s'
            and ts_code in (%s)
            group by ts_code
        ) target
        on ori.ts_code = target.ts_code and
        (ori.trade_date = target.max_dt or ori.trade_date = target.min_dt)
        where target.ts_code is not null
    """ % (
    from_date, to_date, "'" + "','".join(ts_code_list) + "'", from_date, to_date, "'" + "','".join(ts_code_list) + "'")
    price_list = db_client.query_with_sql(sql, MqDailyPrice)

    result = {}
    for p in price_list:  # type: MqDailyPrice
        if p.ts_code not in result:
            result[p.ts_code] = {
                'min_dt': date_utils.format_delta(to_date, 1),
                'max_dt': date_utils.format_delta(from_date, -1),
                'open': None,
                'close': None,
                'ret': None
            }
        if p.trade_date < result[p.ts_code]['min_dt']:
            result[p.ts_code]['min_dt'] = p.trade_date
            result[p.ts_code]['open'] = p.open * p.adj
        if p.trade_date > result[p.ts_code]['max_dt']:
            result[p.ts_code]['max_dt'] = p.trade_date
            result[p.ts_code]['close'] = p.close * p.adj
    for code in result:
        if result[code]['open'] is None or result[code]['close'] is None:
            continue
        result[code]['ret'] = result[code]['close'] / result[code]['open'] - 1
    return result
Exemplo n.º 4
0
def update_dividend_to(to_date: str):
    session: Session = db_client.get_session()
    td: list = session.query(TsDividend).order_by(
        TsDividend.imp_ann_date.desc()).limit(1).all()
    session.close()

    now: str = fetch_data_start_date if len(
        td) == 0 else date_utils.format_delta(td[0].imp_ann_date, 1)

    dt_code_map = {}
    while now <= to_date:
        current = common_fetch_dividend(ts_code=None, dt=now)
        fetch.merge_from_map(dt_code_map, current)
        now = date_utils.format_delta(now, 1)
    return dt_code_map
Exemplo n.º 5
0
    def get_price_between(self, ts_code_arr: list, now_date: str,
                          from_date: str, to_date: str, adj_type: str) -> list:
        """
        获取股票的每日价格信息
        :param ts_code_arr: 股票编码列表,为空时全取
        :param now_date: 查看数据的日期,会显示当时能看到的前复权价格,需为交易日,不能为空
        :param from_date: 获取价格的时间段 开始时间,不能为空 必须小于等于 now_date
        :param to_date: 获取价格的时间段 结束时间,不能为空 必须小于等于 now_date
        :param adj_type: qfq - 前复权, hfq - 后复权, 其他 - 不复权
        :return: list(MqDailyPrice)
        """
        if now_date is None or not date_utils.is_valid_dt(now_date):
            raise Exception('now_date is empty or invalid')
        if from_date is None or not date_utils.is_valid_dt(from_date):
            raise Exception('from_date is empty or invalid')
        if to_date is None or not date_utils.is_valid_dt(to_date):
            raise Exception('to_date is empty or invalid')
        if from_date > now_date or to_date > now_date:
            raise Exception('Cant get future price %s~%s in %s' %
                            (from_date, to_date, now_date))

        all_date_arr = [now_date]
        i = from_date
        while i < to_date:
            all_date_arr.append(i)
            i = date_utils.format_delta(i, 1)

        mq_list: list = self.get_normal_price_in(ts_code_arr, all_date_arr)
        return self.__convert_to_sim_price(mq_list, adj_type, now_date,
                                           now_date > to_date)
Exemplo n.º 6
0
    def analyse(self):
        d = self.__sd
        max_mv = self.__cash
        last_mv = self.__cash
        max_retrieve = 0
        ra = []
        da = []
        while d <= self.__ed:
            if d in self.__dr:
                record: SimDailyRecord = self.__dr[d]
                mv = record.get_total()
                ret = (mv - last_mv) / last_mv
                if mv > max_mv:
                    max_mv = mv
                last_mv = mv
                retrieve = (max_mv - last_mv) / max_mv
                if retrieve > max_retrieve:
                    max_retrieve = retrieve

                ra.append(float(ret))
                da.append(date_utils.parse_str(d))
            d = date_utils.format_delta(d, 1)
        returns = pd.Series(ra, da)
        pf.plot_returns(returns)
        pyplot.show()
Exemplo n.º 7
0
    def __init__(self, ds: SimDataService, sd: str, ed: str, cash: Decimal = 500000,
                 charge: Decimal = 0.00025, tax: Decimal = 0.001, pass_tax: Decimal = 0.00002):
        """
        :param ds: 获取数据服务
        :param sd: 回测开始日期
        :param ed: 回测结束日期
        :param cash: 起始现金
        :param charge: 交易费率 - 券商佣金
        :param tax: 印花税率
        :param pass_tax: 过户费率
        """
        self.__sd = sd  # 回测开始日期
        self.__ed = ed  # 回测结束日期
        self.__init_cash = Decimal(cash)  # 初始现金
        self.__cash = Decimal(cash)  # 现金
        self.__charge = Decimal(charge)  # 交易费率 - 券商佣金
        self.__tax = Decimal(tax)  # 印花税率
        self.__pass = Decimal(pass_tax)  # 过户费率

        self.__data = ds
        self.__sz, self.__sh = ds.get_trade_calendar(sd, ed)  # 深沪市交易日历

        self.__shares = {}  # 拥有的股票
        self.__shares_just_buy = {}  # 当日买的股票
        self.__dividend = {}  # 登记了分红送股的
        self.__records = {}  #
        self.__orders = {}  # 订单
        self.__price = {}  # 每日价格信息,只保存当天的

        self.__cd = format_delta(sd, -1)  # 当前日期
        self.next_day()  # 进入下一个交易日
        self.info('Ready for simulation')

        self.__register_code = set()
        self.__inited = False
Exemplo n.º 8
0
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))
Exemplo n.º 9
0
    def init_cache(self, ts_code_set: set, from_date: str, to_date: str):
        """
        预先缓存指定日期的数据
        :param ts_code_set: 编码列表
        :param from_date: 开始日期
        :param to_date: 结束日期
        :return:
        """
        if from_date is None or not date_utils.is_valid_dt(from_date):
            raise Exception('from_date is empty or invalid')
        if to_date is None or not date_utils.is_valid_dt(to_date):
            raise Exception('to_date is empty or invalid')
        if len(ts_code_set) == 0:
            log.warn('No ts code to cache, skip')
            return

        all_date_arr = []
        i = from_date
        while i < to_date:
            all_date_arr.append(i)
            i = date_utils.format_delta(i, 1)
        mq_list: list = self.get_normal_price_in(ts_code_set, all_date_arr)
        for p in mq_list:  # type: MqDailyPrice
            d = p.trade_date
            if d not in self.__cache:
                self.__cache[d] = []
            self.__cache[d].append(p)
        log.info("Cache init: mq_price")
Exemplo n.º 10
0
 def default_previous_trade_date(self, dt: str):
     session: Session = db_client.get_session()
     cal_arr = session.query(TsTradeCal).filter(TsTradeCal.is_open == '1', TsTradeCal.cal_date < dt) \
         .order_by(TsTradeCal.cal_date.desc()).limit(1).all()
     session.close()
     return cal_arr[0].cal_date if len(
         cal_arr) > 0 else date_utils.format_delta(dt, -1)
Exemplo n.º 11
0
def extract_from_dividend(result_list: list, store: MqQuarterStore,
                          period_dict: dict, d: TsDividend):
    # 有可能有非固定分红的派钱
    lp: str = date_utils.latest_period_date(d.end_date)
    update_date: str = date_utils.format_delta(d.imp_ann_date, -1)

    call_add_nx = partial(add_nx,
                          ts_code=d.ts_code,
                          period=lp,
                          update_date=update_date,
                          report_type=mq_report_type.report,
                          store=store,
                          result_list=result_list,
                          period_dict=period_dict)

    # 叠加到最近一个季度的分红中
    dividend: Decimal = decimal_utils.mul(d.cash_div_tax, d.base_share)
    if lp != d.end_date:
        ori_d: MqQuarterMetric = store.find_period_latest(
            ts_code=d.ts_code,
            period=lp,
            update_date=update_date,
            name=mq_quarter_metric_enum.dividend.name)
        if ori_d is not None:
            dividend = dividend + ori_d.value
    call_add_nx(name='dividend', value=dividend)
Exemplo n.º 12
0
def fetch_from_date(exchange: str):
    session: Session = db_client.get_session()
    result = session.query(func.max(
        TsTradeCal.cal_date)).filter(TsTradeCal.exchange == exchange).all()
    session.close()
    from_date = fetch_data_start_date
    if len(result) > 0 and not result[0][0] is None:
        from_date = date_utils.format_delta(result[0][0], day_num=1)
    return from_date
Exemplo n.º 13
0
def fetch_from_date(ts_code: str = None):
    s: Session = db_client.get_session()
    result = s.query(func.max(TsCashFlow.mq_ann_date)) \
        .filter(TsCashFlow.ts_code == ts_code if ts_code is not None else True) \
        .all()
    s.close()
    from_date = fetch_data_start_date
    if len(result) > 0 and not result[0][0] is None:
        from_date = date_utils.format_delta(result[0][0], day_num=-7)
    return from_date
Exemplo n.º 14
0
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
Exemplo n.º 15
0
def run(to_date: str = date_utils.get_current_dt()):
    dt_code_map = {}

    # 股票基础信息
    init_ts_basic.init()
    # 交易日历
    fetch_trade_cal.fetch(to_date)

    trade_date_service.refresh_cache(fetch_data_start_date,
                                     date_utils.format_delta(to_date, 30))

    to_fetch_list = [
        # 同花顺指数
        fetch_ths_index.run,
        # 券商金股
        fetch_broker_recommend.fetch,
        # 分红记录
        fetch_dividend.update_dividend_to,
        # 每日指标
        fetch_daily_basic.fetch_by_date,
        # 每日交易
        fetch_daily_bar.fetch_by_date,
        # 复权因子
        fetch_adj_factor.fetch_by_date,
        # 涨跌停价格
        fetch_stk_limit.fetch_by_date,
        # 利润表
        fetch_income.fetch_by_period,
        # 资产负债表
        fetch_balance_sheet.fetch_by_period,
        # 现金流量表
        fetch_cash_flow.fetch_by_period,
        # 预报
        fetch_forecast.fetch_by_period,
        # 快报
        fetch_express.fetch_by_period,
        # 财务指标
        fetch_fina_indicator.fetch_by_period
    ]

    if env_utils.parallel():
        fl = []
        for func in to_fetch_list:
            fl.append(threadpool.submit(func, to_date=to_date))
        for f in fl:
            m = f.result()
            if m is not None:
                fetch.merge_from_map(dt_code_map, m)
    else:
        for func in to_fetch_list:
            m = func(to_date=to_date)
            if m is not None:
                fetch.merge_from_map(dt_code_map, m)

    return dt_code_map
Exemplo n.º 16
0
def extract_from_manual(result_list: list, store: MqQuarterStore,
                        period_dict: dict, manual: MqManualMetric):
    add_nx(ts_code=manual.ts_code,
           period=manual.period,
           update_date=date_utils.format_delta(manual.update_date, -1),
           report_type=manual.report_type,
           store=store,
           result_list=result_list,
           period_dict=period_dict,
           name=manual.name,
           value=manual.value)
Exemplo n.º 17
0
def fetch_from_date(date_column: dict(type=str,
                                      help='对应发布日期的字段名 用于获取该类型数据在DB中最新日期'),
                    code_column: dict(type=str, help='对应股票编码的字段名'),
                    ts_code: dict(type=str, help='股票编码')):
    session: Session = db_client.get_session()
    result = session.query(
        func.max(date_column)).filter(code_column == ts_code).all()
    from_date = fetch_data_start_date
    if len(result) > 0 and not result[0][0] is None:
        from_date = date_utils.format_delta(result[0][0], day_num=1)
    session.close()
    return from_date
Exemplo n.º 18
0
def extract_from_income_adjust(result_list: list, store: MqQuarterStore,
                               period_dict: dict, income: TsIncome):
    update_date = date_utils.format_delta(income.mq_ann_date, -1)

    nprofit_new = store.find_period_exact(income.ts_code,
                                          mq_quarter_metric_enum.nprofit.name,
                                          income.end_date, update_date)
    nprofit_old = store.find_period_latest(
        income.ts_code, mq_quarter_metric_enum.nprofit.name, income.end_date,
        date_utils.format_delta(update_date, -1))
    dprofit_old = store.find_period_latest(
        income.ts_code, mq_quarter_metric_enum.dprofit.name, income.end_date,
        date_utils.format_delta(update_date, -2))

    to_add = None
    if nprofit_new is None:
        log.error('Cant find nprofit in adjust income. %s %s' %
                  (income.ts_code, income.end_date))
    elif nprofit_old is None or dprofit_old is None:
        to_add = MqQuarterMetric(
            ts_code=income.ts_code,
            report_type=(1 << mq_report_type.report_adjust),
            period=income.end_date,
            update_date=update_date,
            name=mq_quarter_metric_enum.dprofit.name,
            value=nprofit_new.value)
    else:
        to_add = MqQuarterMetric(
            ts_code=income.ts_code,
            report_type=(1 << mq_report_type.report_adjust),
            period=income.end_date,
            update_date=update_date,
            name=mq_quarter_metric_enum.dprofit.name,
            value=decimal_utils.sub(
                nprofit_new.value,
                decimal_utils.sub(nprofit_old.value, dprofit_old.value)))

    if to_add is not None:
        common_add(result_list, store, to_add)
Exemplo n.º 19
0
def get_from_date(index_code):
    """
    获取指标已有的最大日期,计算从哪开始补数
    :param index_code: 指标代码
    :return:
    """
    s: Session = db_client.get_session()
    result = s.query(func.max(MqIndexTradeAmount.trade_date)).filter(
        MqIndexTradeAmount.index_code == index_code).all()
    s.close()
    from_date = mq_calculate_start_date
    if len(result) > 0 and result[0][0] is not None:
        from_date = date_utils.format_delta(result[0][0], day_num=1)
    return from_date
Exemplo n.º 20
0
def extract_from_fina_indicator(result_list: list, store: MqQuarterStore,
                                period_dict: dict, fina: TsFinaIndicator):
    call_add_nx = partial(add_nx,
                          ts_code=fina.ts_code,
                          period=fina.end_date,
                          update_date=date_utils.format_delta(
                              fina.ann_date, -1),
                          report_type=mq_report_type.report,
                          store=store,
                          result_list=result_list,
                          period_dict=period_dict)

    for i in mq_quarter_metric_enum.extract_from_fi_list:
        call_add_nx(name=i.name, value=getattr(fina, i.from_name))
Exemplo n.º 21
0
def extract_from_express(result_list: list, store: MqQuarterStore,
                         period_dict: dict, express: TsExpress):
    call_add_nx = partial(add_nx,
                          ts_code=express.ts_code,
                          period=express.end_date,
                          update_date=date_utils.format_delta(
                              express.ann_date, -1),
                          report_type=mq_report_type.express,
                          store=store,
                          result_list=result_list,
                          period_dict=period_dict)

    for i in mq_quarter_metric_enum.extract_from_express_list:
        call_add_nx(name=i.name, value=getattr(express, i.from_name))
Exemplo n.º 22
0
def extract_from_balance(result_list: list, store: MqQuarterStore,
                         period_dict: dict, bs: TsBalanceSheet):
    call_add_nx = partial(add_nx,
                          ts_code=bs.ts_code,
                          period=bs.end_date,
                          update_date=date_utils.format_delta(
                              bs.mq_ann_date, -1),
                          report_type=mq_report_type.report if bs.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_bs_list:
        call_add_nx(name=i.name, value=getattr(bs, i.from_name))
Exemplo n.º 23
0
def cal_by_ths_index_code(index_code,
                          index_name,
                          to_date: str = date_utils.get_current_dt()):
    from_date = get_from_date(index_code)
    history_avl = get_history_percent(index_code, from_date)

    s: Session = db_client.get_session()
    member_list = s.query(ThsMember).filter(
        ThsMember.ts_code == index_code).all()
    s.close()

    share_code_list = [m.code for m in member_list]
    result_list = []
    while from_date <= to_date:
        log.info('Calculating %s %s %s' %
                 (MqIndexTradeAmount.__tablename__, index_code, from_date))
        s: Session = db_client.get_session()
        trade_list = s.query(TsDailyTradeInfo) \
            .filter(TsDailyTradeInfo.trade_date == from_date) \
            .all()
        s.close()
        if len(trade_list) > 0:
            total_amount = Decimal(0)
            target_amount = Decimal(0)
            for i in trade_list:  # type: TsDailyTradeInfo
                total_amount += i.amount
                if i.ts_code in share_code_list:
                    target_amount += i.amount

            val = float(decimal_utils.div(target_amount, total_amount))
            history_percent = get_history_high_percent(history_avl, val)

            history_avl.add(val)
            result_list.append(
                MqIndexTradeAmount(index_code=index_code,
                                   index_name=index_name,
                                   trade_date=from_date,
                                   amount=target_amount,
                                   percent=val,
                                   history_high_ratio=history_percent))
        from_date = date_utils.format_delta(from_date, 1)
        if len(result_list) >= 1000:
            db_client.batch_insert(result_list)
            result_list = []
    db_client.batch_insert(result_list)
Exemplo n.º 24
0
def extract_from_income(result_list: list, store: MqQuarterStore,
                        period_dict: dict, income: TsIncome):
    call_add_nx = partial(
        add_nx,
        ts_code=income.ts_code,
        period=income.end_date,
        update_date=date_utils.format_delta(income.mq_ann_date, -1),
        report_type=mq_report_type.report
        if income.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_income_list:
        call_add_nx(name=i.name, value=getattr(income, i.from_name))

    # 处理调整 - 净利根据往年调整
    if income.report_type == '4':
        extract_from_income_adjust(result_list, store, period_dict, income)
Exemplo n.º 25
0
    def after_trade(self, context: SimContext, data: SimDataService):
        # 清除已补的缺口,或30天前的缺口
        dt: str = context.get_dt()
        old_dt: str = date_utils.format_delta(dt, -30)
        for ts_code in self.target:
            p: SimDailyPrice = context.get_today_price(ts_code)
            if p is None or p.is_trade == 0:
                # 未上市 或 停牌就不用看了
                continue
            self.last_trade_price[ts_code] = p
            ts_gap: list = self.gap[ts_code]

            if len(ts_gap) == 0:
                continue

            to_remove: list = []
            for gap_price in ts_gap:  # type: SimDailyPrice
                if gap_price.trade_date < old_dt or p.high >= gap_price.low:
                    to_remove.append(gap_price)

            if len(to_remove) > 0:
                for r in to_remove:  # type: SimDailyPrice
                    ts_gap.remove(r)
                log.info('Gap clear: %s %s %.2f. Gap num: %d' %
                         (ts_code, dt, gap_price.low, len(ts_gap)))

        self.yesterday_buy = set()
        just_buy: dict = context.get_holding_just_buy()
        for ts_code in just_buy:  # type: str
            self.yesterday_buy.add(ts_code)

        self.before_yesterday_buy = set()
        old_holdings: dict = context.get_holding()
        for ts_code in old_holdings:  # type: str
            self.before_yesterday_buy.add(ts_code)

        # 新的缺口数目标应该是 max(剩余缺口数+1,标准缺口数)
        for ts_code in self.target:  # type: str
            new_gap_num: int = len(self.gap[ts_code]) + 1
            if new_gap_num < self.standard_gap_num:
                new_gap_num = self.standard_gap_num
            self.gap_num_target[ts_code] = new_gap_num
Exemplo n.º 26
0
def cal_top_amount_share(to_date: str = date_utils.get_current_dt()):
    from_date = get_from_date(mq_index.top_amount_code)
    history_avl = get_history_percent(mq_index.top_amount_code, from_date)

    result_list = []
    while from_date <= to_date:
        log.info('Calculating %s %s %s' %
                 (MqIndexTradeAmount.__tablename__, mq_index.top_amount_code,
                  from_date))
        s: Session = db_client.get_session()
        trade_list = s.query(TsDailyTradeInfo) \
            .filter(TsDailyTradeInfo.trade_date == from_date) \
            .order_by(TsDailyTradeInfo.amount.desc()) \
            .all()
        s.close()
        if len(trade_list) > 0:
            top_to_count = math.floor(len(trade_list) * 0.05)
            total_amount = Decimal(0)
            top_amount = Decimal(0)
            for i in range(len(trade_list)):
                total_amount += trade_list[i].amount
                if i <= top_to_count:
                    top_amount += trade_list[i].amount

            val = float(decimal_utils.div(top_amount, total_amount))
            history_percent = get_history_high_percent(history_avl, val)

            history_avl.add(val)
            result_list.append(
                MqIndexTradeAmount(index_code=mq_index.top_amount_code,
                                   index_name=mq_index.top_amount_name,
                                   trade_date=from_date,
                                   amount=top_amount,
                                   percent=val,
                                   history_high_ratio=history_percent))
        from_date = date_utils.format_delta(from_date, 1)
        if len(result_list) >= 1000:
            db_client.batch_insert(result_list)
            result_list = []
    db_client.batch_insert(result_list)
Exemplo n.º 27
0
def extract_from_forecast(result_list: list, store: MqQuarterStore,
                          period_dict: dict, forecast: TsForecast):
    update_date = date_utils.format_delta(forecast.ann_date, -1)
    call_add_nx = partial(add_nx,
                          ts_code=forecast.ts_code,
                          period=forecast.end_date,
                          update_date=update_date,
                          report_type=mq_report_type.forecast,
                          store=store,
                          result_list=result_list,
                          period_dict=period_dict)

    forecast_nprofit = None
    if forecast.net_profit_min is not None:
        forecast_nprofit = forecast.net_profit_min
    elif forecast.net_profit_max is not None:
        forecast_nprofit = forecast.net_profit_max
    else:
        percent = None
        # choose minimum percent.
        if forecast.p_change_min is not None:
            percent = forecast.p_change_min
        if forecast.p_change_max is not None:
            if percent is None or forecast.p_change_max < percent:
                percent = forecast.p_change_max
        if percent is not None:
            percent = (percent / 100) + 1
            if forecast.last_parent_net is not None:
                forecast_nprofit = percent * forecast.last_parent_net
            else:
                nprofit_ly = store.find_period_latest(
                    forecast.ts_code, mq_quarter_metric_enum.nprofit.name,
                    forecast.end_date, update_date)
                if nprofit_ly is not None and nprofit_ly.value is not None:
                    forecast_nprofit = percent * nprofit_ly.value

    call_add_nx(name=mq_quarter_metric_enum.nprofit.name,
                value=forecast_nprofit)
Exemplo n.º 28
0
def run(dt: str, min_mv=5e10, gap_num=3):
    """
    2022年开始市值 > 500亿
    一个月内出现三个以上向下缺口时买入,只能在新缺口当天买入
    一字跌停缺口不算 少于1%的缺口不算
    买入日回补缺口则次日开盘价卖出
    买入日没回补缺口则次日挂补缺价卖出 最后收盘价无脑卖出

    :param dt: 对应日期
    :param min_mv: 最低市值要求
    :param gap_num: 需要达到多少个缺口
    :return:
    """
    delete_old(dt)
    ts = ts_client.get_ts()
    pro = ts_client.get_pro()
    trade_df = pro.trade_cal(exchange='SSE',
                             start_date=dt,
                             end_date=dt,
                             is_open=1)
    if len(trade_df) == 0:
        log.info('[Down Gap] Not trade date')
        return

    trade_df = pro.trade_cal(exchange='SSE',
                             start_date='20220101',
                             end_date=dt,
                             is_open=1)
    first_trade_date = trade_df.iloc[0]['cal_date']

    basic = pro.daily_basic(trade_date=first_trade_date,
                            fields=['ts_code', 'total_mv'])
    start = date_utils.format_delta(dt, -30)

    info = pro.stock_basic(fields=["ts_code", "name"]).set_index('ts_code')
    candidate_num = 0

    for ts_code in basic.loc[basic['total_mv'] * 10000 > min_mv]['ts_code']:
        log.info('[Down Gap] %s' % ts_code)
        strategy_record = []
        gap_record = {}
        from_dt = start
        last_price = None
        price_df = ts.pro_bar(ts_code=ts_code, start_date=from_dt,
                              adj='qfq').set_index('trade_date')
        current_trade = None
        while from_dt <= dt:
            can_buy_today = current_trade is None  # 如果今天持股,即使有卖出也不该再买入了
            if from_dt not in price_df.index:  # 非交易日
                from_dt = date_utils.format_delta(from_dt, 1)
                continue
            current_price = price_df.loc[from_dt]
            if last_price is not None:
                # 判断是否应该无脑卖出 按开盘价卖出
                if current_trade is not None and current_trade['should_sell']:
                    current_trade['sell_date'] = from_dt
                    current_trade['sell_price'] = current_price['open']
                    strategy_record.append(current_trade)
                    current_trade = None

                # 先判断开盘有没有下缺口
                if current_price['open'] < last_price['low'] and last_price[
                        'low'] / current_price['open'] > 1.01:
                    down_limit = current_price['open'] == current_price['close'] and current_price['open'] == \
                                 current_price['high'] and current_price['open'] == current_price['low']
                    new_gap = {
                        'trade_date': from_dt,
                        'low': last_price['low'],
                        'high': current_price['open'],
                        'down_limit': down_limit
                    }
                    gap_record[from_dt] = new_gap

                # 达到3个下缺口时按开盘价买入
                if can_buy_today and can_buy(gap_record, from_dt, gap_num):
                    current_trade = {
                        'ts_code': ts_code,
                        'buy_date': from_dt,
                        'buy_price': current_price['open'],
                        'target_price': last_price['low'],
                        'should_sell': False
                    }

                # 判断最高价回补了多少个缺口
                high = current_price['high']
                for d in list(gap_record.keys()):
                    if high >= gap_record[d]['low']:  # 补缺了
                        del (gap_record[d])
                    elif from_dt >= date_utils.format_delta(d, 30):  # 超过30天了
                        del (gap_record[d])
                    elif current_price['high'] > gap_record[d]['high']:
                        gap_record[d]['high'] = current_price['high']

                # 判断今天有没有卖出
                if current_trade is not None:
                    if high >= current_trade['target_price']:  # 补缺了
                        # 当天买的,卖不了,等第二天
                        if current_trade['buy_date'] == from_dt:
                            current_trade['should_sell'] = True
                        else:
                            current_trade['sell_date'] = from_dt
                            current_trade['sell_price'] = current_trade[
                                'target_price']
                            strategy_record.append(current_trade)
                            current_trade = None
                    else:  # 没补缺 看是不是收盘卖
                        if current_trade['buy_date'] != from_dt:
                            current_trade['sell_date'] = from_dt
                            current_trade['sell_price'] = current_price[
                                'close']
                            strategy_record.append(current_trade)
                            current_trade = None

            last_price = current_price
            from_dt = date_utils.format_delta(from_dt, 1)

        if len(strategy_record) > 0:
            last_trade = strategy_record[-1]
            if last_trade['buy_date'] == dt:  # 今日买入
                strategy_buy = MqStrategyTrade(
                    strategy=__strategy,
                    strategy_version=__version,
                    strategy_intro=__wiki,
                    ts_code=ts_code,
                    share_name=info.loc[ts_code]['name'],
                    buy_date=last_trade['buy_price'],
                    buy_price=last_trade['buy_date'])
                db_client.batch_insert([strategy_buy])
            elif last_trade['sell_date'] == dt:  # 今日卖出
                s: Session = db_client.get_session()
                s.query(MqStrategyTrade).filter(
                    MqStrategyTrade.strategy == __strategy,
                    MqStrategyTrade.strategy_version == __version,
                    MqStrategyTrade.ts_code == ts_code,
                    MqStrategyTrade.buy_date ==
                    last_trade['buy_date']).delete()
                s.close()
                strategy_sell = MqStrategyTrade(
                    strategy=__strategy,
                    strategy_version=__version,
                    strategy_intro=__wiki,
                    ts_code=ts_code,
                    share_name=info.loc[ts_code]['name'],
                    buy_date=last_trade['buy_date'],
                    buy_price=last_trade['buy_price'],
                    sell_date=last_trade['sell_date'],
                    sell_price=last_trade['sell_price'])
                db_client.batch_insert([strategy_sell])

        if valid_gap_num(gap_record, dt) == gap_num - 1:
            to_insert = MqSharePool(
                dt=dt,
                strategy=__strategy,
                ts_code=ts_code,
                share_name=info.loc[ts_code]['name'],
                suggest_price=decimal_utils.cal_price_with_gain_percent(
                    current_price['low'], -1),
                suggest_comment='次日下缺口超1%买入')
            db_client.batch_insert([to_insert])
            candidate_num += 1

    log.info('[Down Gap] Done. Dt: %s. Total: %d' % (dt, candidate_num))
Exemplo n.º 29
0
                                     from_date=from_date,
                                     to_date=to_date)


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.next_period(to_date)
    from_period = fetch_from_period()
    return fetch.common_fetch_report_by_period(TsCashFlow,
                                               'fetch_cash_flow',
                                               TsCashFlow.end_date,
                                               from_period=from_period,
                                               to_period=to_period)


if __name__ == '__main__':
    trade_date_service.refresh_cache(
        fetch_data_start_date,
        date_utils.format_delta(date_utils.get_current_dt(), 30))
    print(fetch_by_date())
Exemplo n.º 30
0
    to_date = trade_date_service.get_next_trade_date(to_date)
    from_date = fetch_from_date()
    trade_date_service.refresh_cache(trade_date_service.get_previous_trade_date(from_date), to_date)
    return fetch.common_fetch_report(TsExpress, 'fetch_express',
                                     TsExpress.ts_code, TsExpress.mq_ann_date,
                                     from_date=from_date, to_date=to_date)


def fetch_from_period():
    s: Session = db_client.get_session()
    result = s.query(func.max(TsExpress.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.next_period(to_date)
    from_period = fetch_from_period()
    return fetch.common_fetch_report_by_period(
        TsExpress, 'fetch_express', TsExpress.end_date,
        from_period=from_period, to_period=to_period)


if __name__ == '__main__':
    trade_date_service.refresh_cache(fetch_data_start_date, date_utils.format_delta(date_utils.get_current_dt(), 30))
    print(fetch_by_date())