async def test_load_bars_batch(self): codes = ["000001.XSHE", "000001.XSHG"] # end = arrow.now(tz=cfg.tz).datetime # async for code, bars in Security.load_bars_batch(codes, end, 10, # FrameType.MIN30): # print(bars[-2:]) # self.assertEqual(10, len(bars)) # # codes = ['000001.XSHE', '000001.XSHG'] end = arrow.get("2020-08-27").datetime async for code, bars in Security.load_bars_batch( codes, end, 5, FrameType.DAY): print(code, bars[-2:]) self.assertEqual(5, len(bars)) self.assertEqual(bars[-1]["frame"], end.date()) if code == "000001.XSHG": self.assertAlmostEqual(3350.11, bars[-1]["close"], places=2)
async def distribution(self): # 涨停、跌停 zt, dt = 0, 0 codes = Securities().choose(['stock']) end = arrow.now(cfg.tz).floor('minute').datetime pct = [] async for code, bars in Security.load_bars_batch( codes, end, 2, FrameType.DAY): c1, c0 = bars[-2:]['close'] if (c0 + 0.01) / c1 - 1 > 0.1: zt += 1 if (c0 - 0.01) / c1 - 1 < -0.1: dt += 1 pct.append(c0 / c1 - 1) # 分布 cuts = np.histogram( pct, bins=[-0.2, -0.1, -0.07, -0.03, 0, 0.03, 0.07, 0.1, 0.2]) self.price_change_history.append((zt, dt, cuts)) if len(self.price_change_history) == 8: self.price_change_history.pop(0) now = arrow.now(tz=cfg.tz) if now.hour >= 15: dt = tf.date2int(now) await cache.sys.hset( f"glance{dt}", "distribution", json.dumps({ "zt": zt, "dt": dt, "cuts": cuts })) return zt, dt, cuts
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)
async def test_something(self): end = arrow.get('2020-8-27 10:00:00').datetime async for code, bars in Security.load_bars_batch(['300589.XSHE'], end, 26, FrameType.DAY): print(code, bars[-1])