Exemple #1
0
    def run(self, start=None, end=None):
        if self.data is None or self.data.empty:
            util_log_info('{} {} quote data is empty'.format(
                self.code, self.freq))
            return

        self.data.apply(self.on_bar, axis=1)
Exemple #2
0
    def on_bar(self, bar):
        """
        bar 格式
        date 默认为 Timestamp,主要时画图函数使用
        """
        bar = bar.to_dict()
        # if 'trade' in bar:
        #     bar['vol'] = bar.pop('trade')
        # bar['date'] = pd.to_datetime(bar['date'])
        self.bars.append(bar)

        try:
            self.update()
        except Exception as error:
            util_log_info(error)
Exemple #3
0
    def to_df(self):
        xd = self.xd_list
        index = 0
        sig = []
        while xd:
            df = pd.DataFrame(xd.sig_list)
            df['xd'] = index
            df['code'] = self.code
            df['exchange'] = self.exchange
            sig.append(df)
            xd = xd.next
            index = index + 1

        try:
            sig_df = pd.concat(sig).set_index(['date', 'xd']).sort_index()
            return sig_df
        except:
            util_log_info("{} signal is empty!".format(self.code))
            return pd.DataFrame()
Exemple #4
0
def update_fx(bars, new_bars: list, fx_list: list, trade_date: list):
    """更新分型序列
    k线中有direction,fx中没有direction字段
        分型记对象样例:
         {
             'date': Timestamp('2020-11-26 00:00:00'),
              'fx_mark': -1, 低点用—1表示
              'value': 138.0,
              'fx_start': Timestamp('2020-11-25 00:00:00'),
              'fx_end': Timestamp('2020-11-27 00:00:00'),
          }
         {
             'date': Timestamp('2020-11-26 00:00:00'),
              'fx_mark': +1, 高点用+1表示
              'value': 150.67,
              'fx_start': Timestamp('2020-11-25 00:00:00'),
              'fx_end': Timestamp('2020-11-27 00:00:00'),
          }
        """
    assert len(bars) > 0
    bar = bars[-1].copy()

    if len(trade_date) > 1:
        if TradeDate(bar['date']) < TradeDate(trade_date[-1]):
            util_log_info('{} data is older than {} !'.format(
                bar['date'], trade_date[-1]))
            return

    trade_date.append(bar['date'])

    # 第1根K线没有方向,不需要任何处理
    if len(bars) < 2:
        new_bars.append(bar)
        return False

    last_bar = new_bars[-1]

    cur_h, cur_l = bar['high'], bar['low']
    last_h, last_l, last_dt = last_bar['high'], last_bar['low'], last_bar[
        'date']

    # 处理过包含关系,只需要用一个值识别趋势
    direction = identify_direction(cur_h, last_h)

    # 第2根K线只需要更新方向
    if len(bars) < 3:
        bar.update(direction=direction)
        new_bars.append(bar)
        return False

    last_direction = last_bar.get('direction')

    # 没有包含关系,需要进行分型识别,趋势有可能改变
    if (cur_h > last_h and cur_l > last_l) or (cur_h < last_h
                                               and cur_l < last_l):
        new_bars.append(bar)
        # 分型识别
        if last_direction * direction < 0:

            bar.update(direction=direction)
            if direction < 0:
                fx = {
                    "date": last_bar['date'],
                    "fx_mark": 1,
                    "value": last_bar['high'],
                    "fx_start": new_bars[-3]['date'],  # 记录分型的开始和结束时间
                    "fx_end": bar['date'],
                    # "direction": bar['direction'],
                }
            else:
                fx = {
                    "date": last_bar['date'],
                    "fx_mark": -1,
                    "value": last_bar['low'],
                    "fx_start": new_bars[-3]['date'],  # 记录分型的开始和结束时间
                    "fx_end": bar['date'],
                    # "direction": bar['direction'],
                }
            fx_list.append(fx)
            return True
        bar.update(direction=last_direction + np.sign(last_direction))
        return False

    # 有包含关系,不需要进行分型识别,趋势不改变,direction数值增加
    bar.update(direction=last_direction + np.sign(last_direction))
    new_bars.pop(-1)  # 有包含关系的前一根数据被删除,这里是个技巧
    # 有包含关系,按方向分别处理,同时需要更新日期
    if last_direction > 0:
        if cur_h < last_h:
            bar.update(high=last_h, date=last_dt)
        if cur_l < last_l:
            bar.update(low=last_l)
    elif last_direction < 0:
        if cur_l > last_l:
            bar.update(low=last_l, date=last_dt)
        if cur_h > last_h:
            bar.update(high=last_h)
    else:
        logging.error('{} last_direction: {} is wrong'.format(
            last_dt, last_direction))
        raise ValueError

    new_bars.append(bar)
    return False
Exemple #5
0
    def update_xd(self):
        """更新笔分型序列
        分型记对象样例:
         {
             'date': Timestamp('2020-11-26 00:00:00'),
              'fx_mark': -8,  低点,负数,表示下降趋势持续的K线根数
              'value': 138.0,
              'fx_start': Timestamp('2020-11-25 00:00:00'),
              'fx_end': Timestamp('2020-11-27 00:00:00'),
          }

         {
             'date': Timestamp('2020-11-26 00:00:00'),
              'fx_mark': 7, 高点, 正数,表示上升趋势持续的根数
              'value': 150.67,
              'fx_start': Timestamp('2020-11-25 00:00:00'),
              'fx_end': Timestamp('2020-11-27 00:00:00'),
          }
        """
        # 至少3根同类型分型才可能出现线段,最后1根bi不确定,因此最后一段也不确定
        if self.next is None:
            self.next = XdList(self.bars, self.indicators, self.trade_date)

        bi_list = self.xd_list
        xd_list = self.next

        if len(bi_list) < 4:
            return False

        if len(xd_list) < 1:
            # 线段不存在,初始化线段,找4个点的最高和最低点组成线段
            bi_list = bi_list[:-1].copy()
            bi_list = sorted(bi_list, key=lambda x: x['value'], reverse=False)
            if TradeDate(bi_list[0]['date']) < TradeDate(bi_list[-1]['date']):
                xd_list.append(bi_list[0])
                xd_list.append(bi_list[-1])
            else:
                xd_list.append(bi_list[-1])
                xd_list.append(bi_list[0])

            xd_list.update_xd_eigenvalue()
            return True

        bi3 = bi_list[-3]
        xd = bi_list[-1].copy()
        last_xd = xd_list[-1]
        xd2 = xd_list[-2]

        # if xd['date'] > pd.to_datetime('2016-07-12'):
        #     print('test')

        # 非分型结尾段,直接替换成分型, 没有新增段,后续不需要处理,同一个端点确认
        if 'direction' in last_xd or xd['date'] == last_xd['date']:
            xd_list[-1] = xd  # 日期相等的情况是否已经在内存中修改过了?
            xd_list.update_xd_eigenvalue()
            return True

        # assert xd['date'] > last_xd['date']
        if TradeDate(xd['date']) <= TradeDate(last_xd['date']):
            util_log_info('The {} quotes bar input maybe wrong!'.format(
                xd['date']))

        if bi3['fx_mark'] > 0:
            # 同向延续
            if last_xd['fx_mark'] > 0 and xd['value'] > last_xd['value']:
                xd_list[-1] = xd
                xd_list.update_xd_eigenvalue()
                return True
            # 反向判断
            elif last_xd['fx_mark'] < 0:
                # 价格判断
                if xd['value'] > xd2['value']:
                    xd_list.append(xd)
                    xd_list.update_xd_eigenvalue()
                    return True
                # 出现三笔破坏线段,连续两笔,一笔比一笔高,寻找段之间的最高点
                elif TradeDate(bi3['date']) > TradeDate(
                        last_xd['date']) and xd['value'] > bi3['value']:
                    index = -5
                    bi = bi_list[index]
                    # 连续两个高点没有碰到段前面一个低点
                    try:
                        if TradeDate(bi['date']) < TradeDate(last_xd['date']) and \
                                bi_list[index - 1]['value'] > bi3['value'] and \
                                bi_list[index]['value'] > xd['value']:
                            return False
                    except Exception as err:
                        pass
                        # util_log_info('Last xd {}:{}'.format(last_xd['date'], err))

                    while TradeDate(bi['date']) > TradeDate(last_xd['date']):
                        if xd['value'] < bi['value']:
                            xd = bi
                        index = index - 2
                        bi = bi_list[index]
                    xd_list.append(xd)
                    xd_list.update_xd_eigenvalue()
                    return True
        elif bi3['fx_mark'] < 0:
            # 同向延续
            if last_xd['fx_mark'] < 0 and xd['value'] < last_xd['value']:
                xd_list[-1] = xd
                xd_list.update_xd_eigenvalue()
                return True
            # 反向判断
            elif last_xd['fx_mark'] > 0:
                # 价格判断
                if xd['value'] < xd2['value']:
                    xd_list.append(xd)
                    xd_list.update_xd_eigenvalue()
                    return True
                # 出现三笔破坏线段,连续两笔,一笔比一笔低,将最低的一笔作为段的起点,避免出现最低点不是端点的问题
                elif TradeDate(bi3['date']) > TradeDate(
                        last_xd['date']) and xd['value'] < bi3['value']:
                    index = -5
                    bi = bi_list[index]
                    # 连续两个个低点没有碰到段前面一高低点
                    try:
                        if TradeDate(bi['date']) < TradeDate(last_xd['date']) and \
                                bi_list[index - 1]['value'] < bi3['value'] and \
                                bi_list[index]['value'] < xd['value']:
                            return False
                    except Exception as err:
                        pass
                        # util_log_info('Last xd {}:{}'.format(last_xd['date'], err))

                    while TradeDate(bi['date']) > TradeDate(last_xd['date']):
                        if xd['value'] > bi['value']:
                            xd = bi
                        index = index - 2
                        bi = bi_list[index]
                    xd_list.append(xd)
                    xd_list.update_xd_eigenvalue()
                    return True
        return False
Exemple #6
0
def calculate_bs_signals(security_df: pd.DataFrame, last_trade_date=None):
    sig_list = []

    if last_trade_date is None:
        last_trade_date = util_get_real_date(
            datetime.today().strftime('%Y-%m-%d'))

    last_trade_time = pd.to_datetime(util_get_next_day(last_trade_date))
    last_trade_date = pd.to_datetime(last_trade_date)

    index = 0

    for code, item in security_df.iterrows():
        exchange = item['exchange']
        util_log_info("============={} {} Signal==========".format(
            code, exchange))
        try:
            czsc_day = CzscMongo(code=code,
                                 end=last_trade_date,
                                 freq='day',
                                 exchange=exchange)
        except Exception as error:
            util_log_info("{} : {}".format(code, error))
            continue

        if len(czsc_day.data) < 1:
            util_log_info("==========={} {} 0 Quotes==========".format(
                code, exchange))
            continue

        if czsc_day.data.iloc[-1]['date'] < last_trade_date:
            util_log_info("=={} {} last trade date {}==".format(
                code, exchange,
                czsc_day.data.iloc[-1]['date'].strftime('%Y-%m-%d')))
            continue

        czsc_day.run()
        sig_day_list = czsc_day.sig_list

        if len(sig_day_list) < 1:
            continue

        last_day_sig = sig_day_list[-1]

        if last_day_sig['date'] < last_trade_date:
            util_log_info("===={} {} last Signal {}====".format(
                code, exchange, last_day_sig['date'].strftime('%Y-%m-%d')))
            continue

        # 流动性过滤,future为成交量过滤
        if item['instrument'] == 'future':
            amount = czsc_day.bars[-1]['volume']
            if amount < 10000:
                util_log_info("===={} {} volume is few!====".format(
                    code, exchange))
                continue
        elif exchange in ['hkconnect']:
            amount = czsc_day.bars[-1]['hk_stock_amount']
        else:
            amount = czsc_day.bars[-1]['amount']
            if amount < 10000000:
                util_log_info("===={} {} amount is few!====".format(
                    code, exchange))
                continue

        # 笔中枢走势的起点,如果是上升趋势的买点,从当前中枢的最高点开始计算,如果是卖点,从上升趋势的起点开始
        xd_list = czsc_day.xd_list
        zs_list = xd_list.zs_list

        if len(zs_list) < 1:
            continue

        xd_mark = last_day_sig['xd_mark']
        # if xd_mark < 0:
        #     xd = zs_list[-1]['DD'][-1]
        # else:
        #     xd = zs_list[-1]['GG'][-1]
        #
        # start = xd.get('fx_start')
        start = xd_list.sig_list[-1]['start']

        czsc_min = CzscMongo(code=code,
                             start=start,
                             end=last_trade_time,
                             freq='5min',
                             exchange=exchange)

        try:
            if len(czsc_min.data) < 1:
                util_log_info("========={} {} 0 5min Quotes========".format(
                    code, exchange))
                continue
        except:
            util_log_info(
                "========={} {} 5min Quotes file is not exists!========".
                format(code, exchange))
            continue

        if czsc_min.data.iloc[-1]['date'] < last_trade_date:
            util_log_info("==Please Update {} {} 5min Quotes from {}==".format(
                code, exchange,
                czsc_day.data.iloc[-1]['date'].strftime('%Y-%m-%d')))
            continue

        czsc_min.run()

        sig_min_list = czsc_min.sig_list

        if len(sig_min_list) < 1:
            continue

        last_min_sig = sig_min_list[-1]

        if last_min_sig['date'] < last_trade_date:
            continue

        df = pd.DataFrame(sig_min_list).set_index('date')

        bar_df = pd.DataFrame(czsc_min.bars).set_index('date')
        bar_df = bar_df[bar_df.index > last_trade_date]

        if xd_mark > 0:
            idx = bar_df['low'].idxmin()
        else:
            idx = bar_df['high'].idxmax()

        if df.empty:
            util_log_info("===Please Download {} {} 5min Data===".format(
                code, exchange))
            continue

        try:
            last_min_sig = df.loc[idx].to_dict()
        except:
            util_log_info("{} {} Have a opposite Signal=======".format(
                code, exchange))
            continue

        if last_min_sig['xd_mark'] * xd_mark < 0:  # 日内高低点不一定是高级别买卖点
            util_log_info("{} {} Have a opposite Signal=======".format(
                code, exchange))
            continue

        # 顺趋势买卖点为1,-1,逆趋势级别要大,小于0为逆趋势,或者不为笔分型
        # (xd_mark * zs_list[-1]['location'] <= 0 and last_min_sig['xd'] >= 2)
        # (xd_mark * zs_list[-1]['location'] >= 0 and last_min_sig['xd_mark'] in [1, -1])
        # ('fx_start' in xd_list[-1])
        if not ((xd_mark * zs_list[-1]['location'] <= 0
                 and last_min_sig['xd'] >= 2) or
                (xd_mark * zs_list[-1]['location'] >= 0
                 and last_min_sig['xd_mark'] in [1, -1]) or
                ('fx_start' in xd_list[-1])):
            util_log_info("==={} xd:{}, xd_mark:{}===".format(
                code, last_min_sig['xd'], last_min_sig['xd_mark']))
            continue

        try:
            dif = 0 if np.isnan(
                last_min_sig.get('dif')) else last_min_sig.get('dif')
            macd = 0 if np.isnan(
                last_min_sig.get('macd')) else last_min_sig.get('macd')
            last_min_sig.update(macd=dif + macd)
        except TypeError:
            util_log_info("{} {} has no macd value=======".format(
                code, exchange))

        # if code in ['515120', '510310', '512500', '515380', '515390', '515800', '159905']:
        #     print('ok')

        for idx in range(1, last_min_sig['xd'] + 1):
            dif = 0 if np.isnan(last_min_sig.get(
                'dif{}'.format(idx))) else last_min_sig.get(
                    'dif{}'.format(idx))
            macd = 0 if np.isnan(last_min_sig.get(
                'macd{}'.format(idx))) else last_min_sig.get(
                    'macd{}'.format(idx))
            last_min_sig.update(macd=last_min_sig.get('macd') + dif + macd)

        for key in last_min_sig:
            last_day_sig[key + '_min'] = last_min_sig[key]

        # last_day_sig['start'] = start

        last_day_sig.update(amount=amount, code=code, exchange=exchange)

        sig_list.append(last_day_sig)

        index = index + 1
        util_log_info("==={:=>4d}. {} {} Have a Signal=======".format(
            index, code, exchange))

    if len(sig_list) < 1:
        util_log_info("========There are 0 Signal=======")
        return None

    df = pd.DataFrame(sig_list)
    columns = df.columns.to_list()
    # order = df.columns.sort_values(ascending=False).drop(['date', 'location', 'location_min', 'exchange'])

    order = [
        'code',
        'xd',
        'real_loc',
        'xd_mark',
        'weight',
        'boll',
        'dif',
        'macd',
        'start',
        'xd_min',
        'real_loc_min',
        'xd_mark_min',
        'weight_min',
        'boll_min',
        'macd_min',
        'amount',
    ]

    idx = 1
    day_index = order.index('start')

    while 'dif{}'.format(idx) in columns:
        order.insert(day_index, 'dif{}'.format(idx))
        if 'macd{}'.format(idx) in columns:
            day_index = day_index + 1
            order.insert(day_index, 'macd{}'.format(idx))

        day_index = day_index + 1
        idx = idx + 1

    df = df[order].sort_values(by=['xd', 'xd_min', 'macd_min', 'weight'],
                               ascending=[False, False, False, False])

    util_log_info("===There are {} Signal=======".format(index))
    return df