Beispiel #1
0
    async def scan(self, stop: Frame = None):
        start = tf.shift(stop, -26, FrameType.WEEK)
        ERR = {5: 0.008, 10: 0.004, 20: 0.004}

        for code in Securities().choose(['stock']):
            #for code in ['002150.XSHE']:
            sec = Security(code)
            bars = await sec.load_bars(start, stop, FrameType.WEEK)
            if bars[-1]['frame'] != stop:
                raise ValueError("")

            t1, t2, t3 = False, False, False
            params = []
            for win in [5, 10, 20]:
                ma = signal.moving_average(bars['close'], win)
                err, (a, b, c), (vx, _) = signal.polyfit(ma[-7:] / ma[-7])
                if err > ERR[win]:
                    continue

                p = np.poly1d((a, b, c))
                slp3 = round(p(9) / p(6) - 1, 2)

                params.append(np.round([slp3, a, b], 4))
                if win == 5:
                    t1 = slp3 >= 0.03 and a > 0.005
                if win == 10:
                    t2 = slp3 >= 0.02 and (b > abs(10 * a) or a > 0.0005)
                if win == 20:
                    t3 = slp3 >= -1e-6 and a >= 0

            if all([t1, t2, t3]):
                print(sec.display_name, params)
Beispiel #2
0
    def test_polyfit_inflextion(self):
        bars = stocks.get_bars('000001.XSHG', 100, '30m')

        ma20 = signal.moving_average(bars['close'], 20)
        peaks, valleys = signal.polyfit_inflextion(ma20, 10)

        print(peaks, valleys)
Beispiel #3
0
    async def fire_long(self,
                        end: Frame,
                        frame_type: FrameType.DAY,
                        win=60,
                        adv=0.03):
        secs = Securities()
        results = []
        for code in secs.choose(['stock']):
            #for code in ['601238.XSHG']:
            sec = Security(code)
            if sec.name.find("ST") != -1 or sec.code.startswith("688"):
                continue

            start = tf.shift(end, -win + 1, frame_type)
            bars = await sec.load_bars(start, end, frame_type)
            ilow = np.argmin(bars['low'])
            if ilow > win // 2:  #创新低及后面的反弹太近,信号不可靠
                continue

            low = bars['low'][ilow]
            last = bars['low'][-5:]
            if np.count_nonzero((last > low) & (last < low * 1.02)) < 3:
                # 对新低的测试不够
                continue

            c1, c0 = bars['close'][-2:]
            # 今天上涨幅度是否大于adv?
            if c0 / c1 - 1 < adv:
                continue
            # 是否站上5日线10日线?
            ma5 = signal.moving_average(bars['close'], 5)
            ma10 = signal.moving_average(bars['close'], 10)

            if c0 < ma5[-1] or c0 < ma10[-1]: continue

            price_change = await sec.price_change(end, tf.day_shift(end, 5),
                                                  frame_type)
            print(f"FIRED:{end}\t{code}\t{price_change:.2f}")
            results.append([end, code, price_change])

        return results
Beispiel #4
0
async def predict_ma(code: str,
                     frame_type: FrameType = FrameType.DAY,
                     end: Frame = None):
    """
    预测ma5、ma10、ma20的下一个数据
    Args:
        code:
        frame_type:
        end:

    Returns:

    """
    sec = Security(code)
    start = tf.shift(end, -29, frame_type)
    bars = await sec.load_bars(start, end, frame_type)

    c0 = bars['close'][-1]

    target = [c0 * (1 + f / 100) for f in range(-3, 3)]

    for c in target:
        close = np.append(bars['close'], c)
        ma5 = signal.moving_average(close, 5)
        ma10 = signal.moving_average(close, 10)
        ma20 = signal.moving_average(close, 20)

        fig = plt.figure()
        axes = plt.subplot(111)
        axes.plot([i for i in range(27)],
                  close[-27:],
                  color='#000000',
                  linewidth=0.5)  # len(ma5) == 27
        axes.plot(ma5)
        axes.plot([i for i in range(5, len(ma10) + 5)], ma10)
        axes.text(26, ma10[-1], f"{ma10[-1]:.2f}")
        axes.plot([i for i in range(15, len(ma20) + 15)], ma20)
        axes.text(26, c, f"{c:.2f}")
        axes.text(
            0.5, 3450,
            f"{100 * (c / c0 - 1):.2f}% {c:.2f} {ma5[-1]:.2f} {ma10[-1]:.2f}")
Beispiel #5
0
async def plot_ma(code: str,
                  groups=None,
                  end: Frame = None,
                  frame_type: FrameType = FrameType.DAY):
    groups = groups or [5, 10, 20, 60, 120]
    sec = Security(code)
    end = end or tf.floor(arrow.now(), frame_type)
    start = tf.shift(end, -(groups[-1] + 19), frame_type)
    bars = await sec.load_bars(start, end, frame_type)

    for win in groups:
        ma = signal.moving_average(bars['close'], win)
        plt.plot(ma[-20:])
Beispiel #6
0
    async def scan_1(self,
                     ma_win: int,
                     frame_type: FrameType,
                     a: float = None,
                     b: float = None,
                     err=1e-3,
                     end: Frame = None):
        """
        在所有股票中,寻找指定均线强于拟合均线(a,b,1)的,如果当前收盘价在均线附近,且近期存在
        大阳线,则发出信号
        Returns:

        """
        if a is None:
            err = self.ref_lines[f"ma{ma_win}"].get("err")
            a, b = self.ref_lines[f"ma{ma_win}"].get("coef")

        fit_win = 7
        secs = Securities()
        p = np.poly1d((a, b, 1.0))
        slp3 = p(fit_win - 1 + 3) / p(fit_win - 1) - 1
        count = 0
        for i, code in enumerate(secs.choose(['stock'])):
            if (i + 1) % 500 == 0:
                logger.debug("handled %s", i + 1)
            sec = Security(code)

            bars = await self.get_bars(code, fit_win + 19, frame_type, end)
            ma = signal.moving_average(bars['close'], ma_win)
            err_, (a_, b_,
                   c_), (vx_, _) = signal.polyfit(ma[-fit_win:] / ma[-fit_win])
            if err_ > err:
                continue

            #p_ = np.poly1d((a_,b_,1.0))
            # 如果abs(b) < fit_win * a,曲线(在x不超过fit_win的地方)接近于直线,此时应该比较b
            t5, t10, t20 = False, None, None
            #slp3_5 = p_(fit_win+2)/p_(fit_win-1) - 1
            t5 = a_ >= a * 0.99 and fit_win + 1 >= vx_ >= fit_win - 2
            if t5:
                print(f"{sec.display_name},{vx_:.1f}")
Beispiel #7
0
def ma_lines_trend(bars: np.array, ma_wins: List[int]):
    """
    从bars数据中提取均线的走势特征
    Args:
        bars:
        ma_wins:

    Returns:

    """
    features = {}
    for win in ma_wins:
        ma = signal.moving_average(bars['close'], win)
        fit_win = 7 if win == 5 else 10
        err, (a, b, c), (vx, _) = signal.polyfit(ma[-fit_win:] / ma[-fit_win])
        p = np.poly1d((a, b, c))

        # 预测一周后均线涨幅
        war = p(fit_win + 5 - 1) / p(fit_win - 1) - 1

        features[f"ma{win}"] = [ma, (err, a, b, vx, fit_win, war)]

    return features
Beispiel #8
0
    async def copy(self,
                   code: str,
                   frame_type: FrameType,
                   end: Frame,
                   ma_win=5):
        fit_win = 7

        sec = Security(code)
        start = tf.shift(end, -(ma_win + fit_win), frame_type)
        bars = await sec.load_bars(start, end, frame_type)
        ma = signal.moving_average(bars['close'], ma_win)
        err, (a, b, c), (vx, _) = signal.polyfit(ma[-fit_win:] / ma[-fit_win])
        p = np.poly1d((a, b, c))
        slp3 = p(fit_win + 2) / p(fit_win - 1) - 1
        print(
            f"{sec.display_name}({code})\t{err:.4f}\t{a:.4f}\t{b:.4f}\t{vx:.1f}\
        \t{slp3:.2f}")
        self.ref_lines[f"ma{ma_win}"] = {
            "err": err,
            "coef": (a, b),
            "vx": vx,
            "slp3": slp3
        }
Beispiel #9
0
    async def evaluate(self, code: str, end: Frame):
        """
        最近穿越年线的股票,回归到[5,10,20]日均线时,如果均线形态良好,则提示买入
        Args:
            code:
            end:

        Returns:

        """
        start = tf.shift(tf.floor(end, FrameType.DAY), -26, FrameType.DAY)

        sec = Security(code)

        bars = await sec.load_bars(start, end, FrameType.DAY)
        close = bars['close']
        c0 = close[-1]

        # 检查接近5日均线,要求5日内强于均线,均线不能向下(或者拐头趋势)
        ma = signal.moving_average(close, 5)
        err, (a, b, c), (vx, _) = signal.polyfit(ma[-7:] / ma[-7])

        t1 = np.all(close[-5:] > ma[-5:])
        t2 = err < 3e-3
        t3 = a > 5e-4 or (abs(a) < 1e-5 and b > 1e-3)
        t4 = (c0 - ma[-1] / c0 < 5e-3)
        t5 = vx < 6

        logger.debug("%s 5日:%s, (a,b):%s,%s", sec, [t1, t2, t3, t4, t5], a, b)
        if all([t1, t2, t3, t4, t5]):
            logger.info("fired 5日买入:%s", sec)

            await emit.emit("/alpha/signals/long", {
                "plot":  "crossyear",
                "code":  code,
                "frame": str(end),
                "desc":  "回探5日线",
                "coef":  np.round([a, b], 4),
                "vx":    vx,
                "c":     c0,
                "ma":    ma[-5:]
            })
            return

        # 检查接近20日线买点
        ma = signal.moving_average(close, 20)
        err, (a, b, c), (vx, _) = signal.polyfit(ma[-10:] / ma[-10])

        t1 = err < 3e-3
        t2 = a > 5e-4 or (abs(a) < 1e-5 and b > 5e-3)
        t3 = (c0 - ma[-1]) < 5e-3
        t4 = vx < 9

        logger.debug("%s 20日:%s, (a,b):%s,%s", sec, [t1, t2, t3, t4], a, b)
        if all([t1, t2, t3, t4]):
            logger.info("fired 20日买入:%s", sec)
            await emit.emit("/alpha/signals/long", {
                "plot":  "crossyear",
                "code":  code,
                "frame": str(end),
                "desc":  "回探20日线",
                "coef":  np.round([a, b], 4),
                "vx":    vx,
                "c":     c0,
                "ma":    ma[-5:]
            })
            return

        # 检查是否存在30分钟买点
        start = tf.shift(tf.floor(end, FrameType.MIN30), -30, FrameType.MIN30)
        bars = await sec.load_bars(start, end, FrameType.MIN30)

        close = bars['close']
        ma = signal.moving_average(close, 5)
        err, (a, b, c), (vx, _) = signal.polyfit(ma[-7:] / ma[-7])
        t1 = err < 3e-3
        t2 = a > 5e-4 or (abs(a) < 1e-5 and b > 1e-2)
        t3 = vx < 6

        logger.debug("%s 30分钟:%s, (a,b)", sec, [t1, t2, t3, t4, t5], a, b)
        if all([t1, t2, t3]):
            logger.info("fired 30分钟买入:%s", sec)
            await emit.emit("/alpha/signals/long", {
                "plot":  "crossyear",
                "code":  code,
                "frame": str(end),
                "desc":  "30分钟买点",
                "vx":    vx,
                "c":     c0,
                "ma":    ma[-5:]
            })
Beispiel #10
0
    async def scan(self, end: Frame = None,
                   frame_type: FrameType = FrameType.DAY,
                   codes=None,
                   adv_limit=0.3):
        """
        Args:
            end:
            adv_limit: 不包括在win周期内涨幅超过adv_limit的个股

        Returns:

        """
        win = 20
        secs = Securities()
        end = end or tf.floor(arrow.now(), FrameType.DAY)

        results = []
        holdings = await cache.sys.smembers("holdings")
        for i, code in enumerate(secs.choose(['stock'])):
            try:
                if code in holdings:  # 如果已经持仓,则不跟踪评估
                    continue

                sec = Security(code)
                if sec.code.startswith('688') or sec.display_name.find('ST') != -1:
                    continue

                start = tf.day_shift(end, -270)
                bars = await sec.load_bars(start, end, FrameType.DAY)

                close = bars['close']
                ma5 = signal.moving_average(close, 5)
                ma250 = signal.moving_average(close, 250)

                cross, idx = signal.cross(ma5[-win:], ma250[-win:])
                cross_day = bars[-win + idx]['frame']

                if cross != 1:
                    continue

                ma20 = signal.moving_average(close, 20)
                ma120 = signal.moving_average(close, 120)

                # 如果上方还有月线和ma120线,则不发出信号,比如广州浪奇 2020-7-23,泛海控股2020-8-3
                if close[-1] < ma120[-1] or close[-1] < ma20[-1]:
                    continue

                # 计算20日以来大阳次数。如果不存在大阳线,认为还未到上涨时机,跳过
                grl, ggl = features.count_long_body(bars[-20:])
                if grl == 0:
                    continue

                #
                # # 计算突破以来净余买量(用阳线量减去阴线量来模拟,十字星不计入)
                # bsc = bars[-10 + idx:]  # bars_since_open: included both side
                # ups = bsc[bsc['close'] > (bsc['open'] * 1.01)]
                # downs = bsc[bsc['open'] > (bsc['close'] * 0.99)]
                # balance = np.sum(ups['volume']) - np.sum(downs['volume'])

                # pc = await sec.price_change(cross_day, tf.day_shift(cross_day, 5),
                #                             FrameType.DAY, return_max=True)

                #
                faf = int(win - idx)  # frames after fired
                adv = await sec.price_change(tf.day_shift(end, -win), end,
                                             FrameType.DAY, False)
                if adv > adv_limit:
                    continue

                logger.info(f"{sec}上穿年线\t{cross_day}\t{faf}")
                await cache.sys.hmset_dict("plots.crossyear", {code: json.dumps({
                    "fired_at":  tf.date2int(end),
                    "cross_day": tf.date2int(cross_day),
                    "faf":       faf,
                    "grl":       grl,
                    "ggl":       ggl,
                    "status":    0  # 0 - generated by plots 1 - disabled manually
                })})
                results.append(
                        [sec.display_name, tf.date2int(end), tf.date2int(cross_day),
                         faf, grl,
                         ggl])
            except Exception as e:
                logger.exception(e)

        logger.info("done crossyear scan.")
        return results
Beispiel #11
0
    def screen(self,
               frame,
               end_dt=None,
               adv_lim=25,
               win=7,
               a5=0.02,
               a10=0.001):
        all = []
        fired = []
        if end_dt is None:
            end_dt = arrow.now().datetime

        for i, code in enumerate(stocks.all_stocks()):
            try:
                name = stocks.name_of(code)
                if name.endswith("退"):
                    continue
                if name.find("ST") != -1:
                    continue

                bars = stocks.get_bars(code, 30, frame, end_dt=end_dt)
                if len(bars) == 0:
                    print("get 0 bars", code)
                    continue

                if arrow.get(bars['date'].iat[-1]).date() != arrow.get(
                        end_dt).date():
                    continue

                # 30日涨幅必须小于adv_lim
                if bars['close'].iat[-1] / bars['close'].min(
                ) >= 1 + adv_lim / 100:
                    print(f"{code}涨幅大于", adv_lim)
                    continue

                ma5 = np.array(moving_average(bars['close'], 5))
                ma10 = np.array(moving_average(bars['close'], 10))

                err5, coef5, vertex5 = polyfit(ma5[-win:])
                err10, coef10, vertex10 = polyfit(ma10[-win:])

                vx5, _ = vertex5
                vx10, _ = vertex10
                _a5 = coef5[0]
                _a10 = coef10[0]
                all.append([code, _a5, _a10, vx5, vx10, err5, err10])

                # print(code, round_list([err5, vx, pred_up, y5, ma5[-1], y10, ma10[-1]],3))
                # 如果曲线拟合较好,次日能上涨up%以上,10日线也向上,最低点在win/2以内
                t1 = err5 <= 0.003 and err10 <= 0.003
                t2 = _a5 > a5 and _a10 > a10
                t3 = (win - 1 > vx5 >= win / 2 - 1) and (vx10 < win / 2 - 1)
                if t1 and t2 and t3:
                    c1, c0 = bars['close'].iat[-2], bars['close'].iat[-1]
                    if stocks.check_buy_limit(c1, c0, name):  # 跳过涨停的
                        continue

                    print(f"{stocks.name_of(code)} {code}",
                          [_a5, _a10, vx5, vx10, err5, err10])
                    fired.append([code, _a5, _a10, vx5, vx10, err5, err10])
            except Exception as e:
                print(i, e)
                continue
        return DataFrame(
            data=all,
            columns=['code', 'a5', 'a10', 'vx5', 'vx10', 'err_5', 'err_10'])
Beispiel #12
0
    async def fire_long(self,
                        end: Frame = None,
                        overlap_win=10,
                        frame_type: FrameType = FrameType.MIN30):
        """
        寻找开多仓信号
        Args:

        Returns:

        """
        result = []
        end = end or arrow.now().datetime
        secs = Securities()
        for code in secs.choose(['stock']):
            #for code in ['600139.XSHG']:
            try:
                sec = Security(code)
                start = tf.shift(end, -(60 + overlap_win - 1), frame_type)
                bars = await sec.load_bars(start, end, frame_type)

                mas = {}
                for win in [5, 10, 20, 60]:
                    ma = signal.moving_average(bars['close'], win)
                    mas[f"{win}"] = ma

                # 收盘价高于各均线值
                c1, c0 = bars['close'][-2:]
                t1 = c0 > mas["5"][-1] and c0 > mas["10"][-1] and c0 > mas["20"][-1] \
                     and c0 > mas["60"][-1]

                # 60均线斜率向上
                slope_60, err = signal.slope(mas["60"][-10:])
                if err is None or err > 5e-4:
                    continue

                t2 = slope_60 >= 5e-4

                # 均线粘合
                diff = np.abs(mas["5"][-6:-1] -
                              mas["10"][-6:-1]) / mas["10"][-6:-1]
                overlap_5_10 = np.count_nonzero(diff < 5e-3)
                t3 = overlap_5_10 > 3

                diff = np.abs(mas["10"][-10:] -
                              mas["60"][-10:]) / mas["60"][-10:]
                overlap_10_60 = np.count_nonzero(diff < 5e-3)
                t4 = overlap_10_60 > 5

                price_change = await sec.price_change(
                    end, tf.shift(end, 8, frame_type), frame_type)
                result.append(
                    [end, code, t1, t2, t3, t4, slope_60, price_change, True])

                if t1 and t2 and t3 and t4:
                    print("FIRED:", [
                        end, code, t1, t2, t3, t4, slope_60, price_change, True
                    ])

            except Exception as e:
                pass

        return result
Beispiel #13
0
    async def scan(self,
                   frame_type: Union[str, FrameType] = FrameType.DAY,
                   end: Frame = None,
                   codes: List[str] = None):
        logger.info("running momentum scan at %s level", frame_type)
        if end is None:
            end = arrow.now(cfg.tz).datetime

        assert type(end) in (datetime.date, datetime.datetime)

        frame_type = FrameType(frame_type)
        ft = frame_type.value
        codes = codes or Securities().choose(['stock'])
        day_bars = {}
        async for code, bars in Security.load_bars_batch(
                codes, end, 2, FrameType.DAY):
            day_bars[code] = bars

        if len(day_bars) == 0:
            return

        async for code, bars in Security.load_bars_batch(
                codes, end, 11, frame_type):
            if len(bars) < 11:
                continue

            fired = bars[-1]['frame']
            day_bar = day_bars.get(code)
            if day_bar is None:
                continue

            c1, c0 = day_bars.get(code)[-2:]['close']
            cmin = min(bars['close'])

            # 还处在下跌状态、或者涨太多
            if c0 == cmin or (c0 / c1 - 1) > self.baseline(f"up_limit"):
                continue

            ma5 = signal.moving_average(bars['close'], 5)

            err, (a, b, c), (vx, _) = signal.polyfit(ma5[-7:] / ma5[-7])
            # 无法拟合,或者动能不足
            if err > self.baseline(f"ma5:{ft}:err") or a < self.baseline(
                    f"ma5:{ft}:a"):
                continue

            # 时间周期上应该是信号刚出现,还在窗口期内
            vx_range = self.baseline(f"ma5:{ft}:vx")
            if not vx_range[0] < vx < vx_range[1]:
                continue

            p = np.poly1d((a, b, c))
            y = p(9) / p(6) - 1
            # 如果预测未来三周期ma5上涨幅度不够
            if y < self.baseline(f"ma5:{ft}:y"):
                continue

            sec = Security(code)

            if frame_type == FrameType.DAY:
                start = tf.shift(tf.floor(end, frame_type), -249, frame_type)
                bars250 = await sec.load_bars(start, end, frame_type)
                ma60 = signal.moving_average(bars250['close'], 60)
                ma120 = signal.moving_average(bars250['close'], 120)
                ma250 = signal.moving_average(bars250['close'], 250)

                # 上方无均线压制
                if (c0 > ma60[-1]) and (c0 > ma120[-1]) and (c0 > ma250[-1]):
                    logger.info("%s, %s, %s, %s, %s, %s", sec, round(a, 4),
                                round(b, 4), round(vx, 1),
                                round(c0 / c1 - 1, 3), round(y, 3))
                    await self.enter_stock_pool(code,
                                                fired,
                                                frame_type,
                                                a=a,
                                                b=b,
                                                err=err,
                                                y=y,
                                                vx=self.fit_win - vx)
            elif frame_type == FrameType.WEEK:
                await self.enter_stock_pool(code,
                                            fired,
                                            frame_type,
                                            a=a,
                                            b=b,
                                            err=err,
                                            y=y,
                                            vx=self.fit_win - vx)
            elif frame_type == FrameType.MIN30:
                await self.fire_trade_signal('long',
                                             code,
                                             fired,
                                             frame_type,
                                             a=a,
                                             b=b,
                                             err=err,
                                             y=y,
                                             vx=self.fit_win - vx)
Beispiel #14
0
    async def evaluate(self,
                       code: str,
                       frame_type: str = '30m',
                       dt: str = None,
                       win=5,
                       flag='long'):
        """
        如果股价从高点下来,或者从低点上来,则发出信号。高点和低点的确定,由于曲线拟合的原因,
        可能产生上一周期未发出信号,这一周期发出信号,但高点或者低点已在几个周期之前。这里的
        策略是,在新的趋势未形成之前,只报一次
        Args:
            code:
            frame_type: frame_type
            dt:
            win:
            flag:

        Returns:

        """
        stop = arrow.get(dt, tzinfo=cfg.tz) if dt else arrow.now(tz=cfg.tz)
        frame_type = FrameType(frame_type)
        ft = frame_type.value

        bars = await self.get_bars(code, win + self.fit_win, frame_type, stop)

        ma = signal.moving_average(bars['close'], win)
        _ma = ma[-self.fit_win:]
        err, (a, b, c), (vx, _) = signal.polyfit(_ma / _ma[0])

        logger.debug("%s, %s, %s, %s, %s", code, err, a, b, vx)
        if err > self.baseline(f"ma{win}:{ft}:err"):
            self.remember(code, frame_type, "trend", "dunno")
            return

        p = np.poly1d((a, b, c))
        y = p(self.fit_win + 2) / p(self.fit_win - 1) - 1

        previous_status = self.recall(code, frame_type, "trend")

        # 如果b > 10 * a * x,则走势主要由b决定。这里x即fit_win序列,我们向后看3周期
        if abs(b) > 10 * (self.fit_win + 3) * abs(a):
            if b > 0 and previous_status != "long" and flag in [
                    'both', "long"
            ]:
                await self.fire_trade_signal('long',
                                             code,
                                             stop,
                                             frame_type,
                                             a=a,
                                             b=b,
                                             err=err,
                                             vx=vx,
                                             y=y)
            if b < 0 and previous_status != "short" and flag in [
                    'both', "short"
            ]:
                await self.fire_trade_signal('short',
                                             code,
                                             stop,
                                             frame_type,
                                             err=err,
                                             a=a,
                                             b=b,
                                             y=y)
            return

        t1 = int(vx) < self.fit_win - 1

        # 判断是否为看多信号
        t2 = a > self.baseline(f"ma{win}:{ft}:a")
        if t1 and t2 and previous_status != "long" and flag in [
                "long", "both"
        ]:
            await self.fire_trade_signal('long',
                                         code,
                                         stop,
                                         frame_type,
                                         err=err,
                                         a=a,
                                         b=b,
                                         y=y)

        # 判断是否为看空信号
        t2 = a < -self.baseline(f"ma{win}:{ft}:a")
        if t1 and t2 and previous_status != "short" and flag in [
                "short", "both"
        ]:
            await self.fire_trade_signal('short',
                                         code,
                                         stop,
                                         frame_type,
                                         err=err,
                                         a=a,
                                         b=b,
                                         y=y)
Beispiel #15
0
    async def visualize(self, code: Union[str, List[str]], frame: Union[str,
                                                                        Frame],
                        frame_type: Union[str, FrameType]):
        """
        将code列表中的股票的动量特征图象化
        Args:
            code:
            frame:
            frame_type:

        Returns:

        """
        import matplotlib.pyplot as plt

        if isinstance(code, str):
            code = [code]

        col = 4
        row = len(code) // col + 1
        plt.figure(figsize=(5 * row * col, 7))
        plt.subplots_adjust(wspace=0.2, hspace=0.2)

        fit_win = 7
        colors = {"5": '#808080', "10": '#00cc80', "20": '#00ccff'}

        frame = arrow.get(frame)
        frame_type = FrameType(frame_type)
        for i, code in enumerate(code):
            _code = code.split(".")[0]
            start = tf.shift(frame, -25, frame_type)
            bars = await Security(code).load_bars(start, frame, frame_type)

            plt.subplot(len(code) // col + 1, col, i + 1)
            y_lim = 0
            text = ""
            for win in [5, 10, 20]:
                ma = signal.moving_average(bars['close'], win)
                _ma = ma[-fit_win:]

                plt.plot(_ma, color=colors[f"{win}"])

                err, (a, b, c), (vx, _) = signal.polyfit(_ma / _ma[0])
                p = np.poly1d((a * _ma[0], b * _ma[0], c * _ma[0]))
                y = p(fit_win + 2) / p(fit_win - 1) - 1

                y_lim = max(y_lim, np.max(_ma))
                if win == 5:
                    text = f"{_code} a:{a:.4f} b:{b:.4f} vx:{vx:.1f} y:{y:.2f}"

                if err < self.baseline(f"ma{win}:{frame_type.value}:err"):
                    # 如果拟合在误差范围内,则画出拟合线
                    plt.plot([p(i) for i in range(len(_ma))],
                             "--",
                             color=colors[f"{win}"])
                    plt.plot([p(i) for i in range(len(_ma))],
                             "o",
                             color=colors[f"{win}"])

                    if 0 < vx < fit_win:
                        plt.plot([vx], p(vx), 'x')

            plt.plot(0, y_lim * 1.035)
            plt.text(0.1, y_lim * 1.02, text, color='r')