Example #1
0
async def sync_bars(frame: str = None, codes: str = None):
    """立即同步行情数据

    如果`frame`, `codes`没有提供,则从配置文件中读取相关信息

    Args:
        frame:
        codes:

    Returns:

    """
    await _init()

    if frame:
        frame_type = FrameType(frame)
        params = sync.read_sync_params(FrameType(frame))
        if codes:
            params["secs"] = list(map(lambda x: x.strip(" "),
                                      codes.split(",")))
        await sync.trigger_bars_sync(frame_type, params, force=True)
        logger.info("request %s,%s send to workers.", params, codes)
    else:
        for frame_type in itertools.chain(tf.day_level_frames,
                                          tf.minute_level_frames):
            params = sync.read_sync_params(frame_type)
            if params:
                await sync.trigger_bars_sync(frame_type, params, force=True)

            logger.info("request %s,%s send to workers.", params, codes)
Example #2
0
async def sync_bars(frame: str = None, codes: str = None):
    """立即同步行情数据

    如果`frame`, `codes`没有提供,则从配置文件中读取相关信息

    Args:
        frame:
        codes:

    Returns:

    """
    await _init()

    if frame:
        frame_type = FrameType(frame)
        params = syncjobs.load_sync_params(frame_type)
        if codes:
            params["cat"] = None
            params["include"] = codes
        await syncjobs.trigger_bars_sync(params, force=True)
        logger.info("request %s,%s send to workers.", params, codes)
    else:
        for frame_type in itertools.chain(tf.day_level_frames, tf.minute_level_frames):
            params = syncjobs.load_sync_params(frame_type)
            if not params:
                continue
            if codes:
                params["cat"] = None
                params["include"] = codes
            await syncjobs.trigger_bars_sync(params, force=True)

            logger.info("request %s,%s send to workers.", params, codes)
Example #3
0
    async def copy(self,
                   code: str,
                   frame_type: Union[str, FrameType],
                   frame: Union[str, Frame],
                   ma_wins=None):
        frame_type = FrameType(frame_type)
        frame = arrow.get(frame, tzinfo=cfg.tz)
        ma_wins = ma_wins or [5, 10, 20]
        fit_win = 7

        stop = frame
        start = tf.shift(stop, -fit_win - max(ma_wins), frame_type)

        sec = Security(code)
        bars = await sec.load_bars(start, stop, frame_type)
        features = []
        for win in ma_wins:
            ma = signal.moving_average(bars['close'], win)
            if len(ma) < fit_win:
                raise ValueError(
                    f"{sec.display_name} doesn't have enough bars for "
                    f"extracting features")

            err, (a, b, c), (vx,
                             _) = signal.polyfit(ma[-fit_win:] / ma[-fit_win])
            features.append((err, (a, b, c), vx))

        return features
Example #4
0
async def list_momentum_pool(day_offset: int = 1, sort_by='y'):
    start = tf.day_shift(arrow.now().date(), -day_offset)
    key = f"plots.momentum.pool"
    recs = await cache.sys.hgetall(key)
    data = []
    for k, v in recs.items():
        frame, code = k.split(":")
        if arrow.get(frame) < arrow.get(start):
            continue

        sec = Security(code)
        v = json.loads(v)

        frame_type = FrameType(v.get("frame_type"))
        fired = tf.int2time(frame) if frame_type in tf.minute_level_frames else \
            tf.int2date(frame)
        data.append({
            "name": sec.display_name,
            "code": code,
            "fired": fired,
            "frame": frame_type.value,
            "y": round(v.get("y"), 2),
            "vx": round(v.get("vx"), 1),
            "a": round(v.get("a"), 4),
            "b": round(v.get("b"), 4),
            "err": round(v.get("err"), 4)
        })

    if len(data) == 0:
        print("no data")
    else:
        df = DataFrame(data)
        df.set_index('fired', inplace=True)
        display(df.sort_values(sort_by))
Example #5
0
    async def evaluate(self,
                       code: str,
                       frame_type: Union[str, FrameType] = '30m',
                       win: int = 5,
                       flag: str = 'both',
                       slip: float = 0.015):
        """
        测试当前股价是否达到均线(frame_type和win指定)附近
        Args:
            code:
            slip:
            params: frame_type, win, flag

        Returns:

        """
        frame_type = FrameType(frame_type)
        bars = await self.get_bars(code, win, frame_type)
        ma = signal.moving_average(bars['close'], win)

        c0 = bars[-1]['close']
        if abs(c0 / ma[-1] - 1) <= slip:
            await self.fire_trade_signal(flag,
                                         code,
                                         bars[-1]['frame'],
                                         frame_type,
                                         slip=slip,
                                         win=win)
Example #6
0
    async def _test_sync_bars(self):
        # fixme: recover this test later
        config_items = [
            [
                {
                    "frame": "1d",
                    "start": "2020-01-01",
                    "delay": 3,
                    "type": [],
                    "include": "000001.XSHE,000004.XSHE",
                    "exclude": "000001.XSHG",
                }
            ]
        ]

        sync_request = []

        async def on_sync_bars(params: dict):
            sync_request.append(params)

        emit.register(Events.OMEGA_DO_SYNC, on_sync_bars)
        for config in config_items:
            cfg.omega.sync.bars = config
            for frame_config in config:
                frame_type = FrameType(frame_config.get("frame"))
                sync_params = frame_config
                await sync.trigger_bars_sync(frame_type, sync_params, force=True)

        await asyncio.sleep(0.2)
        self.assertDictEqual(
            {"start": "2020-01-01", "stop": None, "frame_type": FrameType.DAY},
            sync_request[0],
        )
Example #7
0
    def __init__(self, frame_type: Union[str, FrameType], jitter: str = None):
        """构造函数

        jitter的格式用正则式表达为`r"([-]?)(\\d+)([mshd])"`,其中第一组为符号,'-'表示提前;
        第二组为数字,第三组为单位,可以为`m`(分钟), `s`(秒), `h`(小时),`d`(天)。

        下面的示例构造了一个只在交易日,每30分钟触发一次,每次提前15秒触的trigger。即它的触发时
        间是每个交易日的09:29:45, 09:59:45, ...

        Examples:
            >>> FrameTrigger(FrameType.MIN30, '-15s')
            ... # doctest: +ELLIPSIS
            <triggers.FrameTrigger object at 0x...>

        Args:
            frame_type:
            jitter: 单位秒。其中offset必须在一个FrameType的长度以内
        """
        self.frame_type = FrameType(frame_type)
        if jitter is None:
            _jitter = 0
        else:
            matched = re.match(r"([-]?)(\d+)([mshd])", jitter)
            if matched is None:  # pragma: no cover
                raise ValueError(
                    "malformed. jitter should be [-](number)(unit), "
                    "for example, -30m, or 30s")
            sign, num, unit = matched.groups()
            num = int(num)
            if unit.lower() == "m":
                _jitter = 60 * num
            elif unit.lower() == "s":
                _jitter = num
            elif unit.lower() == "h":
                _jitter = 3600 * num
            elif unit.lower() == "d":
                _jitter = 3600 * 24 * num
            else:  # pragma: no cover
                raise ValueError("bad time unit. only s,h,m,d is acceptable")

            if sign == "-":
                _jitter = -_jitter

        self.jitter = datetime.timedelta(seconds=_jitter)
        if (frame_type == FrameType.MIN1 and abs(_jitter) >= 60
                or frame_type == FrameType.MIN5 and abs(_jitter) >= 300
                or frame_type == FrameType.MIN15 and abs(_jitter) >= 900
                or frame_type == FrameType.MIN30 and abs(_jitter) >= 1800
                or frame_type == FrameType.MIN60 and abs(_jitter) >= 3600
                or frame_type == FrameType.DAY and abs(_jitter) >= 24 * 3600
                # it's still not allowed if offset > week, month, etc. Would anybody
                # really specify an offset longer than that?
            ):
            raise ValueError("offset must be less than frame length")
Example #8
0
 async def evaluate(self,
                    code: str,
                    frame_type: Union[str, FrameType],
                    flag: str,
                    win: int,
                    price: float,
                    slip: float = 0.015):
     frame_type = FrameType(frame_type)
     bars = await self.get_bars(code, 1, frame_type)
     if abs(bars[-1]['close'] / price - 1) <= slip:
         await self.fire_trade_signal(flag, code, bars[-1]['frame'],
                                      frame_type)
Example #9
0
 async def evaluate(self, code: str, frame_type: Union[FrameType, str], flag: str,
                    win: int,
                    c1: float, d1: Frame,
                    c2: float, d2: Frame,
                    slip: float = 0.015):
     frame_type = FrameType(frame_type)
     n1 = tf.count_frames(d1, d2, frame_type)
     slp = (c2 - c1) / n1
     n2 = tf.count_frames(d2, tf.floor(arrow.now(), frame_type),
                          frame_type)
     c_ = c2 + slp * n2
     bars = await self.get_bars(code, 1, frame_type)
     if abs(c_ / bars[-1]['close'] - 1) <= slip:
         await self.fire_trade_signal(flag, code, bars[-1]['frame'], frame_type)
Example #10
0
    async def get_bars_handler(self, request):
        try:
            sec = request.json.get("sec")
            frame_type = FrameType(request.json.get("frame_type"))

            end = arrow.get(request.json.get("end"), tzinfo=cfg.tz)
            end = end.date() if frame_type in tf.day_level_frames else end.datetime
            n_bars = request.json.get("n_bars")
            include_unclosed = request.json.get("include_unclosed", False)

            bars = await aq.get_bars(sec, end, n_bars, frame_type, include_unclosed)

            body = pickle.dumps(bars, protocol=cfg.pickle.ver)
            return response.raw(body)
        except Exception as e:
            logger.exception(e)
            return response.raw(pickle.dumps(None, protocol=cfg.pickle.ver))
Example #11
0
    async def build_train_data(self, save_to: str,
                               frame_type: str = '1d',
                               n=10) -> List:
        await self.init()
        frame_type = FrameType(frame_type)
        data = await self._build_train_data(frame_type, n)
        date = tf.date2int(arrow.now().date())
        path = os.path.abspath(save_to)
        path = os.path.join(path, f"momemtum.{frame_type.value}.tsv")
        with open(path, "w") as f:
            cols = "code,date,a5,b5,err5,a10,b10,err10,a20,b20,err20,y".split(",")
            f.writelines("\t".join(cols))
            f.writelines("\n")
            for item in data:
                f.writelines("\t".join(map(lambda x: str(x), item)))
                f.writelines("\n")

        return data
Example #12
0
async def get_stock_pool(request):
    args = request.args
    frames = int(args.get('frames')[0])
    frame_types = args.getlist("frame_types")

    if frame_types:
        frame_types = [FrameType(frame_type) for frame_type in frame_types]
    else:
        frame_types = tf.day_level_frames
        frame_types.extend(tf.minute_level_frames)

    plots = args.getlist('plots') or ['momentum']

    results = []
    for plot_name in plots:
        plot = create_plot(plot_name)
        results.append(await plot.list_stock_pool(frames, frame_types))

    return response.json(body=results)
Example #13
0
    def test_comparison(self):
        day = FrameType("1d")
        week = FrameType("1w")
        month = FrameType("1M")
        quater = FrameType("1Q")
        year = FrameType("1Y")
        min_1 = FrameType("1m")
        min_5 = FrameType("5m")

        self.assertTrue(week > day)
        self.assertTrue(day < week)
        self.assertTrue(week < month)
        self.assertTrue(month < quater)
        self.assertTrue(quater < year)
        self.assertTrue(min_1, min_5)

        self.assertTrue(day >= day)
        self.assertTrue(day <= day)
Example #14
0
    def __init__(self, frame_type: Union[str, FrameType], jitter: str = None):
        """
        Args:
            frame_type:
            jitter: in seconds unit, offset must within one frame
        """
        self.frame_type = FrameType(frame_type)
        if jitter is None:
            _jitter = 0
        else:
            matched = re.match(r"([-]?)(\d+)([mshd])", jitter)
            if matched is None:
                raise ValueError(
                    "malformed. jitter should be [-](number)(unit), "
                    "for example, -30m, or 30s")
            sign, num, unit = matched.groups()
            num = int(num)
            if unit.lower() == "m":
                _jitter = 60 * num
            elif unit.lower() == "s":
                _jitter = num
            elif unit.lower() == "h":
                _jitter = 3600 * num
            elif unit.lower() == "d":
                _jitter = 3600 * 24 * num
            else:
                raise ValueError("bad time unit. only s,h,m,d is acceptable")

            if sign == "-":
                _jitter = -_jitter

        self.jitter = datetime.timedelta(seconds=_jitter)
        if (frame_type == FrameType.MIN1 and abs(_jitter) >= 60
                or frame_type == FrameType.MIN5 and abs(_jitter) >= 300
                or frame_type == FrameType.MIN15 and abs(_jitter) >= 900
                or frame_type == FrameType.MIN30 and abs(_jitter) >= 1800
                or frame_type == FrameType.MIN60 and abs(_jitter) >= 3600
                or frame_type == FrameType.DAY and abs(_jitter) >= 24 * 3600
                # it's still not allowed if offset > week, month, etc. Would anybody
                # really specify an offset longer than that?
            ):
            raise ValueError("offset must be less than frame length")
Example #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')
Example #16
0
async def quick_scan():
    # fixme
    secs = Securities()

    report = logging.getLogger("quickscan")

    counters = {}
    for sync_config in cfg.omega.sync.bars:
        frame = sync_config.get("frame")
        start = sync_config.get("start")

        if frame is None or start is None:
            logger.warning("skipped %s: required fields are [frame, start]",
                           sync_config)
            continue

        frame_type = FrameType(frame)

        start = arrow.get(start).date()
        start = tf.floor(start, FrameType.DAY)

        stop = sync_config.get("stop") or arrow.now().date()

        if frame_type in tf.minute_level_frames:
            minutes = tf.ticks[frame_type][0]
            h, m = minutes // 60, minutes % 60
            start = datetime.datetime(start.year,
                                      start.month,
                                      start.day,
                                      h,
                                      m,
                                      tzinfo=tz.gettz(cfg.tz))

            stop = datetime.datetime(stop.year,
                                     stop.month,
                                     stop.day,
                                     15,
                                     tzinfo=tz.gettz(cfg.tz))

        counters[frame] = [0, 0]

        codes = secs.choose(sync_config.get("type"))
        include = filter(lambda x: x,
                         sync_config.get("include", "").split(","))
        include = map(lambda x: x.strip(" "), include)
        codes.extend(include)
        exclude = sync_config.get("exclude", "")
        exclude = map(lambda x: x.strip(" "), exclude)
        codes = set(codes) - set(exclude)

        counters[frame][1] = len(codes)
        for code in codes:
            head, tail = await cache.get_bars_range(code, frame_type)
            if head is None or tail is None:
                report.info("ENOSYNC,%s,%s", code, frame)
                counters[frame][0] = counters[frame][0] + 1
                continue

            expected = tf.count_frames(head, tail, frame_type)

            # 'head', 'tail' should be excluded
            actual = (await
                      cache.security.hlen(f"{code}:{frame_type.value}")) - 2
            if actual != expected:
                report.info("ELEN,%s,%s,%s,%s,%s,%s", code, frame, expected,
                            actual, head, tail)
                counters[frame][0] = counters[frame][0] + 1
                continue

            sec = Security(code)
            if start != head:
                if (type(start) == datetime.date and start > sec.ipo_date
                        or (type(start) == datetime.datetime
                            and start.date() > sec.ipo_date)):
                    report.info("ESTART,%s,%s,%s,%s,%s", code, frame, start,
                                head, sec.ipo_date)
                    counters[frame][0] = counters[frame][0] + 1
                    continue
            if tail != stop:
                report.info("EEND,%s,%s,%s,%s", code, frame, stop, tail)
                counters[frame][0] = counters[frame][0] + 1

    return counters
Example #17
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)
Example #18
0
    async def list_stock_pool(self,
                              frames: int,
                              frame_types: List[FrameType] = None):
        key = "plots.momentum.pool"

        recs = await cache.sys.hgetall(key)
        items = []
        now = arrow.now()
        for k, v in recs.items():
            frame, code = k.split(":")

            sec = Security(code)
            v = json.loads(v)

            frame_type = FrameType(v.get("frame_type"))

            if frame_type not in frame_types:
                continue

            latest_frame = tf.floor(now, frame_type)
            start = tf.shift(latest_frame, -frames, frame_type)

            fired = tf.int2time(frame) if frame_type in tf.minute_level_frames else \
                tf.int2date(frame)

            if fired < start:
                continue

            items.append({
                "name": sec.display_name,
                "code": code,
                "fired": str(fired),
                "frame": frame_type.value,
                "y": round(v.get("y"), 2),
                "vx": round(v.get("vx"), 1),
                "a": round(v.get("a"), 4),
                "b": round(v.get("b"), 4),
                "err": round(v.get("err"), 4)
            })

        return {
            "name":
            self.display_name,
            "plot":
            self.name,
            "items":
            items,
            "headers": [{
                "text": '名称',
                "value": 'name'
            }, {
                "text": '代码',
                "value": 'code'
            }, {
                "text": '信号时间',
                "value": 'fired'
            }, {
                "text": '预测涨幅',
                "value": 'y'
            }, {
                "text": '动能',
                "value": 'a'
            }, {
                "text": '势能',
                "value": 'b'
            }, {
                "text": '周期',
                "value": 'frame'
            }, {
                "text": '底部距离(周期)',
                "value": 'vx'
            }, {
                "text": '拟合误差',
                "value": 'err'
            }]
        }
Example #19
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)
Example #20
0
def parse_sync_params(
    frame: Union[str, Frame],
    cat: List[str] = None,
    start: Union[str, datetime.date] = None,
    stop: Union[str, Frame] = None,
    delay: int = 0,
    include: str = "",
    exclude: str = "",
) -> Tuple:
    """按照[使用手册](usage.md#22-如何同步K线数据)中的规则,解析和补全同步参数。

    如果`frame_type`为分钟级,则当`start`指定为`date`类型时,自动更正为对应交易日的起始帧;
    当`stop`为`date`类型时,自动更正为对应交易日的最后一帧。
    Args:
        frame (Union[str, Frame]): frame type to be sync.  The word ``frame`` is used
            here for easy understand by end user. It actually implies "FrameType".
        cat (List[str]): which catetories is about to be synced. Should be one of
            ['stock', 'index']. Defaults to None.
        start (Union[str, datetime.date], optional): [description]. Defaults to None.
        stop (Union[str, Frame], optional): [description]. Defaults to None.
        delay (int, optional): [description]. Defaults to 5.
        include (str, optional): which securities should be included, seperated by
            space, for example, "000001.XSHE 000004.XSHE". Defaults to empty string.
        exclude (str, optional):  which securities should be excluded, seperated by
            a space. Defaults to empty string.

    Returns:
        - codes (List[str]): 待同步证券列表
        - frame_type (FrameType):
        - start (Frame):
        - stop (Frame):
        - delay (int):
    """
    frame_type = FrameType(frame)

    if frame_type in tf.minute_level_frames:
        if stop:
            stop = arrow.get(stop, tzinfo=cfg.tz)
            if stop.hour == 0:  # 未指定有效的时间帧,使用当日结束帧
                stop = tf.last_min_frame(tf.day_shift(stop.date(), 0),
                                         frame_type)
            else:
                stop = tf.floor(stop, frame_type)
        else:
            stop = tf.floor(arrow.now(tz=cfg.tz).datetime, frame_type)

        if stop > arrow.now(tz=cfg.tz):
            raise ValueError(f"请勿将同步截止时间设置在未来: {stop}")

        if start:
            start = arrow.get(start, tzinfo=cfg.tz)
            if start.hour == 0:  # 未指定有效的交易帧,使用当日的起始帧
                start = tf.first_min_frame(tf.day_shift(start.date(), 0),
                                           frame_type)
            else:
                start = tf.floor(start, frame_type)
        else:
            start = tf.shift(stop, -999, frame_type)
    else:
        stop = (stop and arrow.get(stop).date()) or arrow.now().date()
        if stop == arrow.now().date():
            stop = arrow.now(tz=cfg.tz)

        stop = tf.floor(stop, frame_type)
        start = tf.floor(
            (start and arrow.get(start).date()), frame_type) or tf.shift(
                stop, -1000, frame_type)

    secs = Securities()
    codes = secs.choose(cat or [])

    exclude = map(lambda x: x, exclude.split(" "))
    codes = list(set(codes) - set(exclude))

    include = list(filter(lambda x: x, include.split(" ")))
    codes.extend(include)

    return codes, frame_type, start, stop, int(delay)
Example #21
0
 def test_frame_type_convert(self):
     for frame_type in FrameType:
         self.assertEqual(frame_type.to_int(),
                          FrameType.from_int(frame_type.to_int()).to_int())