pyqqq 0.12.183__py3-none-any.whl → 0.12.185__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyqqq might be problematic. Click here for more details.

@@ -246,6 +246,7 @@ class KISSimpleDomesticStock:
246
246
  search_start = first_date + dtm.timedelta(days=i)
247
247
  search_end = min(first_date + dtm.timedelta(days=i + max_days_per_request), last_date)
248
248
 
249
+ CallLimiter().wait_limit_rate(20, scope="kis/inquire_daily_itemchartprice")
249
250
  r = self.stock_api.inquire_daily_itemchartprice(
250
251
  asset_code,
251
252
  search_start,
pyqqq/data/domestic.py CHANGED
@@ -244,7 +244,9 @@ def get_tickers(
244
244
 
245
245
  KRX 거래소에서는 거래정지 종목 등이 포함되어 있으나, NXT 거래소에서는 거래정지 종목이 제외되어 있습니다.
246
246
 
247
- 2018년 1월 1일 데이터 부터 조회 가능합니다. 수정주가는 소수점 첫째 자리에서 반올림합니다.
247
+ KRX 거래소는 2018년 1월 1일 데이터 부터 조회 가능합니다. 수정주가는 소수점 첫째 자리에서 반올림합니다.
248
+
249
+ NXT 거래소는 2025년 3월 4일 데이터 부터 조회 가능합니다. 수정주가는 소수점 첫째 자리에서 반올림합니다.
248
250
 
249
251
  Args:
250
252
  date (Optional[dtm.date]): 조회할 날짜. 기본값은 현재 날짜입니다.
@@ -265,7 +267,7 @@ def get_tickers(
265
267
  - listing_date (str or None): 상장일
266
268
 
267
269
  Raises:
268
- AssertionError: 잘못된 시장 이름이 입력된 경우 오류를 발생시킵니다.
270
+ AssertionError: 잘못된 시장이나 거래소 이름이 입력된 경우 오류를 발생시킵니다.
269
271
  HTTPError: API 요청이 실패했을 때 발생.
270
272
 
271
273
  Examples:
@@ -285,7 +287,10 @@ def get_tickers(
285
287
  "KOSDAQ",
286
288
  ], "market은 'KOSPI' 또는 'KOSDAQ'이어야 합니다."
287
289
 
288
- # TODO: NXT 거래소 2025년 3월 4일 이전 요청 시 에러 발생
290
+ assert exchange in [
291
+ "KRX", "NXT", DataExchange.KRX, DataExchange.NXT
292
+ ], "exchange는 'KRX' 또는 'NXT'이어야 합니다."
293
+
289
294
  exchange = DataExchange.validate(exchange)
290
295
 
291
296
  if date is None:
@@ -294,6 +299,10 @@ def get_tickers(
294
299
  if schedule.full_day_closed:
295
300
  date = get_last_trading_day(date)
296
301
 
302
+ # 2025년 3월 4일 이전 NXT 거래소 요청 시 빈 데이터 반환
303
+ if exchange == DataExchange.NXT and date < dtm.date(2025, 3, 4):
304
+ return pd.DataFrame()
305
+
297
306
  return _get_tickers(date, market, adjusted, exchange)
298
307
 
299
308
 
@@ -28,6 +28,7 @@ class DailyTickers:
28
28
  self._date = get_last_trading_day(self._today)
29
29
  else:
30
30
  self._date = self._today
31
+ self._is_before_today_krx_open = True
31
32
  self._tickers = None
32
33
  self._change_date()
33
34
 
@@ -36,12 +37,12 @@ class DailyTickers:
36
37
 
37
38
  @lru_cache(maxsize=30) # memory_profiler 로 확인 결과 하루치 fetch 결과가 약 2.5MiB
38
39
  @staticmethod
39
- def fetch_tickers(date: dtm.date) -> pd.DataFrame:
40
+ def fetch_tickers(date: dtm.date, exchange: str) -> pd.DataFrame:
40
41
  DailyTickers.logger.debug(f'\tfetch_tickers date={date} cache_info={DailyTickers.fetch_tickers.cache_info()}')
41
- return domestic.get_tickers(date)
42
+ return domestic.get_tickers(date, exchange=exchange)
42
43
 
43
44
  def _change_date(self, date: Optional[dtm.date] = None, force: bool = False):
44
- """_tickers 가 비었거나 날짜가 바뀌었으면 새로 채워넣는다."""
45
+ """_tickers 가 비었거나 날짜가 바뀌었으면 새로 채워넣는다. 8시 50분 이전에는 NXT 거래소 데이터를 사용한다."""
45
46
  if not date:
46
47
  if self._chk_days_passed():
47
48
  self._today = dtm.date.today()
@@ -52,14 +53,27 @@ class DailyTickers:
52
53
  else:
53
54
  date = self._date
54
55
 
56
+ if self._today == date:
57
+ if dtm.datetime.now().time() < dtm.time(8, 50) and not self._is_before_today_krx_open:
58
+ self._is_before_today_krx_open = True
59
+ self._tickers = None
60
+ elif dtm.datetime.now().time() >= dtm.time(8, 50) and self._is_before_today_krx_open:
61
+ self._is_before_today_krx_open = False
62
+ self._tickers = None
63
+ else:
64
+ pass
65
+ else:
66
+ self._is_before_today_krx_open = False
67
+
55
68
  if force:
56
69
  DailyTickers.fetch_tickers.cache_clear()
57
70
  self._tickers = None
58
71
 
59
72
  if self._tickers is None or self._date != date:
60
73
  self._date = date
74
+ exchange = "NXT" if self._is_before_today_krx_open else "KRX"
61
75
  self.logger.debug(f'\tdate changed. date={self._date} wait for get_tickers()')
62
- self._tickers = DailyTickers.fetch_tickers(self._date)
76
+ self._tickers = DailyTickers.fetch_tickers(self._date, exchange=exchange)
63
77
 
64
78
  def get_tickers(self, date: Optional[dtm.date] = None, force: bool = False) -> pd.DataFrame:
65
79
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqqq
3
- Version: 0.12.183
3
+ Version: 0.12.185
4
4
  Summary: Package for quantitative strategy development on the PyQQQ platform
5
5
  License: MIT
6
6
  Author: PyQQQ team
@@ -23,7 +23,7 @@ pyqqq/brokerage/kis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
23
23
  pyqqq/brokerage/kis/domestic_stock.py,sha256=0mEC5B0HXlIMck4BmOw0Ke5utnWeWnRPngbDKW_jqRs,226778
24
24
  pyqqq/brokerage/kis/oauth.py,sha256=jA7QydFEe5NN8t0QSwEhFoFtQiwTP4fr2segcibOXVU,7805
25
25
  pyqqq/brokerage/kis/overseas_stock.py,sha256=9QUkEX13Lev5BcXMfK2GLve4xwFptOd1vXh4lDbrpYw,90096
26
- pyqqq/brokerage/kis/simple.py,sha256=luQtJfuISgtNheV-9UntzUSyrl5ORAo1FjR2LUwIIBI,41940
26
+ pyqqq/brokerage/kis/simple.py,sha256=uNomK4iQj5YLcmh3GMRd4XPyGSNIcEsDtUp0i9SxgMg,42028
27
27
  pyqqq/brokerage/kis/simple_overseas.py,sha256=1DuQBuJosg0mJQV7Ey2N3UOY8F3uOhzPDay4ncothuc,50360
28
28
  pyqqq/brokerage/kis/tr_client.py,sha256=9fTok0d8FmfXw4YxZSdn6T8UTHIG2aN1yMSkiMJUB3c,5530
29
29
  pyqqq/brokerage/multiprocess_tracker.py,sha256=Xx0hSpRZYITBGWjxclOEtNZdHV5agX94s34q1A8EE-Y,7283
@@ -31,7 +31,7 @@ pyqqq/brokerage/tracker.py,sha256=p26APsjzjM_qO3zrsre3GBqUx4G4hBYcc5TLvzfoKg8,24
31
31
  pyqqq/config.py,sha256=55Vqc_pGkdbrBdCV1aLgoH_n5IFxmMC59sbPHId3LoI,498
32
32
  pyqqq/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  pyqqq/data/daily.py,sha256=k4dSiXNnT_J3mo0j_6VDjkGezBieVpIaZT3W_M7EU1Y,8019
34
- pyqqq/data/domestic.py,sha256=2FOYxDGw2W7DGwY61p3uGFb4IWqWUKiNdR3RlewjkCU,30352
34
+ pyqqq/data/domestic.py,sha256=dQ4Aavl1sT_hFzP-DWfdGM5or1TrZCQwVoq6rk71Wds,30776
35
35
  pyqqq/data/index.py,sha256=d5b-8a7IXu7yNJWt1tIe1Mj83NW0ZnQq8nsj2Sl3Gx8,6988
36
36
  pyqqq/data/minutes.py,sha256=i3u-vlZwZq6Qkca7QSJpUXcu4Vb4W46-W0Q1udgy_1c,15373
37
37
  pyqqq/data/overseas.py,sha256=yx7tCZHW8AvjIbtrP4dqIeC6wseRSzbg5ag3dm6H0LY,1234
@@ -47,7 +47,7 @@ pyqqq/utils/array.py,sha256=8E8JW-P1GWzluiqIDuKdUEALZ30AkKRtfxgdrWmu__Q,1747
47
47
  pyqqq/utils/casting.py,sha256=nCHnJQ_F88R22xfnBg58fiJXwHYYnsnk3qSDw_rVIY8,135
48
48
  pyqqq/utils/compute.py,sha256=nM5WUZ7aWnsrcHnKEQT-Omv56lrZJO6LfmDH6tnrg1M,5645
49
49
  pyqqq/utils/copycat.py,sha256=1cMuQKteOuzBbH3aAdsDCH7ZTxTyM6OyJ5Wii7gmBpk,10837
50
- pyqqq/utils/daily_tickers.py,sha256=hVYhfNjGNAFHJTr8bjPmd4Cd6KxCMqD8ctd4E3kBDQA,4623
50
+ pyqqq/utils/daily_tickers.py,sha256=AAXCN1tNZ2mNC_Ah_rM6zLZgZneNUpMTCJRJWsVnWP8,5378
51
51
  pyqqq/utils/display.py,sha256=kFoXw52ODDgbR-ufAKRJdY5NEA7UTikrosZRukEIWFc,1177
52
52
  pyqqq/utils/kvstore.py,sha256=aAWQrs2IugHBPTRUkbYNxCKF9NZe2MCMD5nSj_lVbVw,4586
53
53
  pyqqq/utils/limiter.py,sha256=0zTJitT-14Ve5aeT0zcNEWQGPyY_3FENorF3HS7WPyQ,2643
@@ -58,6 +58,6 @@ pyqqq/utils/mock_api.py,sha256=7EsaVQ9mOVZQAqtQW24isPnk9QTbJII7x3guhFyEMAE,10569
58
58
  pyqqq/utils/position_classifier.py,sha256=tIbZMm_baru0F0qv6QDc5b2-oJYNvmn9HyrRr3xaAXU,14975
59
59
  pyqqq/utils/retry.py,sha256=4mw9MQvgSBC8bTLvDauaCEI5N9tL8upHCk8rSfaVRG8,2066
60
60
  pyqqq/utils/singleton.py,sha256=m6NZ8fwVDpI6U-gUUihMPgVK_NkDh-Z1NSAtjisrpjY,810
61
- pyqqq-0.12.183.dist-info/METADATA,sha256=r6KbKnwJpGx1EkM-XM7fKWW4w4FB_LVT0_a4LI2OMRU,1664
62
- pyqqq-0.12.183.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
- pyqqq-0.12.183.dist-info/RECORD,,
61
+ pyqqq-0.12.185.dist-info/METADATA,sha256=dFDVqCz6QZ1RT0hCLHxAGTa7ssXPDF_oHT_O_9somEg,1664
62
+ pyqqq-0.12.185.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
+ pyqqq-0.12.185.dist-info/RECORD,,