pyqqq 0.12.176__py3-none-any.whl → 0.12.178__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.

pyqqq/backtest/broker.py CHANGED
@@ -314,6 +314,7 @@ class TradingBroker(BaseBroker):
314
314
  result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.KRX)
315
315
  else:
316
316
  result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.KRX)
317
+ result = result.sort_index(ascending=True)
317
318
  return result
318
319
 
319
320
  def get_orderbook(self, code: str, data_exchange: Optional[DataExchange] = None):
@@ -219,7 +219,7 @@ class KISDomesticStock:
219
219
  ]
220
220
 
221
221
  for k in date_keys:
222
- if k in output and len(output[k]) > 0 and output[k] != '0': # NXT 종목이 아닌데 지정한 경우 output[k] 값이 0
222
+ if k in output and len(output[k]) > 0 and output[k] != "0": # NXT 종목이 아닌데 지정한 경우 output[k] 값이 0
223
223
  output[k] = dtm.datetime.strptime(output[k], "%Y%m%d").date()
224
224
 
225
225
  result = {"rt_cd": res_body["rt_cd"], "msg_cd": res_body["msg_cd"], "msg1": res_body["msg1"], "output": output}
@@ -3859,12 +3859,13 @@ class KISDomesticStock:
3859
3859
  모의계좌의 경우, 한 번의 호출에 최대 20건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.
3860
3860
 
3861
3861
  * 당일 전량매도한 잔고도 보유수량 0으로 보여질 수 있으나, 해당 보유수량 0인 잔고는 최종 D-2일 이후에는 잔고에서 사라집니다.
3862
+ * NXT 선택 시: NXT 거래종목만 시세 등 정보가 NXT 기준으로 변동됩니다. KRX 종목들은 그대로 유지됩니다.
3862
3863
 
3863
3864
  Args:
3864
3865
  cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
3865
3866
  acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
3866
3867
  inqr_dvsn (str): 조회구분 - 01:대출일별 02:종목별
3867
- afhr_flpr_yn (str): 시간외단일가여부 - N:기본값 Y:시간외단일가
3868
+ afhr_flpr_yn (str): 시간외단일가여부 - N:기본값 Y:시간외단일가 X:NXT 정규장 (프리마켓, 메인, 애프터마켓)
3868
3869
  fund_sttl_icld_yn (str): 펀드결제분포함여부 - N:포함하지 않음 Y:포함
3869
3870
  prcs_dvsn (str): 처리구분 - 00:전일매매포함 01:전일매매미포함
3870
3871
  ctx_area_fk100 (str): 연속조회검색조건100 - 공란:최초 조회시. 이전 조회 output ctx_area_fk100 값:다음페이지 조회시(2번째부터)
@@ -3939,7 +3940,7 @@ class KISDomesticStock:
3939
3940
  Raise:
3940
3941
  ValueError: API 에러 발생시
3941
3942
  """
3942
- assert afhr_flpr_yn in ["Y", "N"], 'afhr_flpr_yn must be "Y" or "N"'
3943
+ assert afhr_flpr_yn in ["Y", "N", "X"], 'afhr_flpr_yn must be "Y" or "N" or "X"'
3943
3944
  assert inqr_dvsn in ["01", "02"], 'inqr_dvsn must be "01" or "02"'
3944
3945
  assert fund_sttl_icld_yn in ["Y", "N"], 'fund_sttl_icld_yn must be "Y" or "N"'
3945
3946
  assert prcs_dvsn in ["00", "01"], 'prcs_dvsn must be "00" or "01"'
@@ -4,7 +4,7 @@ from pyqqq.brokerage.kis.oauth import KISAuth
4
4
  from pyqqq.data.realtime import get_all_last_trades
5
5
  from pyqqq.datatypes import *
6
6
  from pyqqq.utils.logger import get_logger
7
- from pyqqq.utils.market_schedule import get_market_schedule, get_last_trading_day
7
+ from pyqqq.utils.market_schedule import get_market_schedule, get_last_trading_day, is_full_day_closed
8
8
  from pyqqq.utils.mock_api import with_mock
9
9
  from typing import AsyncGenerator, Dict, List, Optional
10
10
  import asyncio
@@ -164,6 +164,7 @@ class KISSimpleDomesticStock:
164
164
  self.account_no,
165
165
  self.account_product_code,
166
166
  "02",
167
+ "X",
167
168
  tr_cont=tr_cont,
168
169
  ctx_area_fk100=ctx_area_fk100,
169
170
  ctx_area_nk100=ctx_area_nk100,
@@ -199,6 +200,8 @@ class KISSimpleDomesticStock:
199
200
  return "J"
200
201
  elif data_exchange == DataExchange.NXT:
201
202
  return "NX"
203
+ elif data_exchange == DataExchange.UN:
204
+ return "UN"
202
205
  else:
203
206
  raise ValueError("지원하지 않는 거래소입니다.")
204
207
 
@@ -213,6 +216,10 @@ class KISSimpleDomesticStock:
213
216
  """
214
217
  일봉 데이터 검색
215
218
 
219
+ Note:
220
+ - 두 거래소에서 공통으로 거래정지된 종목의 시가/고가/저가/종가는 모두 동일하며, 그 외 값은 모두 0 입니다.
221
+ - NXT 매매체결 종목이 아니거나, NXT 거래소에서 거래가 불가능한 종목을 DataExchange.NXT 또는 DataExchange.UN으로 조회하면, 모든 값은 0 입니다.
222
+
216
223
  Args:
217
224
  asset_code(str): 종목코드
218
225
  first_date(datetime.date): 조회 시작일자
@@ -257,16 +264,22 @@ class KISSimpleDomesticStock:
257
264
  "low": item["stck_lwpr"],
258
265
  "close": item["stck_clpr"],
259
266
  "volume": item["acml_vol"],
267
+ "value": item["acml_tr_pbmn"],
260
268
  }
261
269
  )
262
- chunk.reverse()
263
270
  result.extend(chunk)
264
271
 
265
- df = pd.DataFrame(result)
266
- if not df.empty:
267
- df["date"] = pd.to_datetime(df["date"])
268
- df.set_index("date", inplace=True)
272
+ df = pd.DataFrame(result, columns=["date", "open", "high", "low", "close", "volume", "value"])
273
+ df["date"] = pd.to_datetime(df["date"])
274
+ df.set_index("date", inplace=True)
275
+
276
+ # 조회기간 중 데이터가 없는 날짜는 0 으로 채움
277
+ dates = pd.date_range(start=first_date, end=last_date, freq="B")
278
+ if len(dates) != len(df):
279
+ dates = [date for date in dates if not is_full_day_closed(date)]
280
+ df = df.reindex(dates, fill_value=0)
269
281
 
282
+ df = df.sort_index(ascending=False)
270
283
  return df
271
284
 
272
285
  def get_today_minute_data(
@@ -277,9 +290,14 @@ class KISSimpleDomesticStock:
277
290
  """
278
291
  분봉 데이터 검색
279
292
 
293
+ Note:
294
+ - 시간외 종가, 시간외 단일가 데이터는 포함되어 있지 않습니다.
295
+ - 두 거래소에서 공통으로 거래정지된 종목의 시가/고가/저가/종가는 모두 동일하며, 그 외 값은 모두 0 입니다.
296
+ - NXT 매매체결 종목이 아니거나, NXT 거래소에서 거래가 불가능한 종목을 DataExchange.NXT 또는 DataExchange.UN으로 조회하면, 모든 값은 0 입니다.
297
+
280
298
  Args:
281
299
  asset_code(str): 종목코드
282
- data_exchange(DataExchange): 데이터 거래소 (cf. NXT의 경우 해당되지 않는 종목은 Empty DataFrame이 아니고 모든 값이 0인 DataFrame이 반환됩니다.)
300
+ data_exchange(DataExchange): 데이터 거래소
283
301
 
284
302
  Returns:
285
303
  pd.DataFrame: 분봉 데이터 (시간의 역순)
@@ -288,14 +306,11 @@ class KISSimpleDomesticStock:
288
306
  request_datetime = dtm.datetime.now()
289
307
  request_time = request_datetime.replace(second=0, microsecond=0)
290
308
  result = []
291
- schedule = get_market_schedule(dtm.date.today())
292
- if schedule.full_day_closed:
293
- _last_day = get_last_trading_day()
294
- schedule = get_market_schedule(_last_day)
295
- if data_exchange == DataExchange.NXT:
296
- request_time = dtm.datetime.combine(_last_day, dtm.time(20, 0, 0))
297
- else:
298
- request_time = dtm.datetime.combine(_last_day, schedule.close_time)
309
+ schedule = get_market_schedule(dtm.date.today(), exchange="KRX" if data_exchange == DataExchange.KRX else "NXT")
310
+
311
+ # 만약 현재 시간이 거래소 마감 시간을 지났다면, 마감 시간으로 설정
312
+ if request_time.time() > schedule.close_time:
313
+ request_time = request_datetime.replace(hour=schedule.close_time.hour, minute=schedule.close_time.minute)
299
314
 
300
315
  while True:
301
316
  r = self.stock_api.inquire_time_itemchartprice(
@@ -326,16 +341,10 @@ class KISSimpleDomesticStock:
326
341
 
327
342
  last_item_time = result[-1]["time"]
328
343
  request_time = last_item_time - dtm.timedelta(minutes=1)
329
-
330
- open_time = schedule.open_time
331
-
332
- # FIXME: 넥스트레이드 시장 (수능일 같은 경우 넥스트레이드는 시간 변동 없이 8시 그대로 오픈한다는 얘기가 있어서 확인 필요)
333
- if data_exchange == DataExchange.NXT:
334
- open_time = dtm.time(8, 0, 0)
335
-
336
- if request_time.time() < open_time:
344
+ if request_time.time() < schedule.open_time:
337
345
  break
338
346
 
347
+ # 거래대금, 누적거래량 계산
339
348
  prev_cum_value = None
340
349
  prev_cum_volume = None
341
350
 
pyqqq/data/minutes.py CHANGED
@@ -18,7 +18,7 @@ minuteCache = DiskCacheManager("minute_cache")
18
18
  @minuteCache.memoize()
19
19
  def get_all_minute_data(
20
20
  time: datetime.datetime,
21
- source: str = "ebest",
21
+ source: str = "kis",
22
22
  adjusted: bool = True,
23
23
  exchange: Union[str, DataExchange] = "KRX",
24
24
  ) -> pd.DataFrame:
@@ -31,7 +31,7 @@ def get_all_minute_data(
31
31
 
32
32
  Args:
33
33
  time (datetime.datetime): 조회할 시간
34
- source (str): 데이터를 검색할 API. 'ebest' 또는 'kis'를 지정할 수 있습니다. 기본값은 'ebest'입니다.
34
+ source (str): 데이터를 검색할 API. 'ebest' 또는 'kis'를 지정할 수 있습니다. 기본값은 'kis'입니다.
35
35
  adjusted (bool): 수정주가 여부. 기본값은 True.
36
36
  exchange (Union[str, DataExchange]): 거래소. 기본값은 KRX.
37
37
 
@@ -130,7 +130,7 @@ def get_all_day_data(
130
130
  date: datetime.date,
131
131
  codes: list[str] | str,
132
132
  period: datetime.timedelta = datetime.timedelta(minutes=1),
133
- source: str = "ebest",
133
+ source: str = "kis",
134
134
  adjusted: bool = True,
135
135
  ascending: bool = True,
136
136
  exchange: Union[str, DataExchange] = "KRX",
@@ -146,7 +146,7 @@ def get_all_day_data(
146
146
  date (datetime.date): 데이터를 검색할 날짜.
147
147
  codes (list[str]): 조회할 주식 코드들의 리스트. 최대 20개까지 지정할 수 있습니다.
148
148
  period (datetime.timedelta, optional): 반환된 데이터의 시간 간격. 기본값은 1분입니다. 30초 이상의 값을 30초간격으로 지정할 수 있습니다.
149
- source (str, optional): 데이터를 검색할 API. 'ebest' 또는 'kis'를 지정할 수 있습니다. 기본값은 'ebest'입니다.
149
+ source (str, optional): 데이터를 검색할 API. 'ebest' 또는 'kis'를 지정할 수 있습니다. 기본값은 'kis'입니다.
150
150
  adjusted (bool): 수정주가 여부. 기본값은 True.
151
151
  ascending (bool): 오름차순 여부. 기본값은 True.
152
152
  exchange (Union[str, DataExchange]): 거래소. 기본값은 KRX. (cf. NXT의 경우 해당되지 않는 종목은 Empty DataFrame이 반환됩니다.)
pyqqq/datatypes.py CHANGED
@@ -19,6 +19,8 @@ class DataExchange(Enum):
19
19
  """ 한국거래소 """
20
20
  NXT = "NXT"
21
21
  """ 넥스트레이드 """
22
+ UN = "UN"
23
+ """ 통합 """
22
24
 
23
25
  @classmethod
24
26
  def validate(cls, exchange: Union[str, "DataExchange"]) -> "DataExchange":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqqq
3
- Version: 0.12.176
3
+ Version: 0.12.178
4
4
  Summary: Package for quantitative strategy development on the PyQQQ platform
5
5
  License: MIT
6
6
  Author: PyQQQ team
@@ -5,7 +5,7 @@ pyqqq/ai/domestic.py,sha256=FiJNInRlhcnxG7Jxmz2hDvaLhS8_jn-JFpQMze8Ch9s,1888
5
5
  pyqqq/ai/market_schedule.py,sha256=8HiivwC-xI2EKr8lXS_g4mTj2LYpCQ2QfZsJmIq61O0,818
6
6
  pyqqq/ai/minute.py,sha256=C0sTVkBY4-Vuj8Q9VZ7d9kZYAv963FUX4k3vIvhetng,1754
7
7
  pyqqq/backtest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- pyqqq/backtest/broker.py,sha256=xHqHVXaurnxnSM1ulitTt3Uf-iy5fqa2B3MINGqN_6k,67646
8
+ pyqqq/backtest/broker.py,sha256=k_n4qCu1cPabJUpiTuqLcUx3lhJopPV2u1mqgzvKtp0,67697
9
9
  pyqqq/backtest/environment.py,sha256=bkdlwG9MynuNL1u7f0cQ1L271cnPqJ7gX89EYwl8oOg,9313
10
10
  pyqqq/backtest/logger.py,sha256=BmoEMjUU76z8rZtMCYCwbspD3AVaHJrdbbT1EAFgrAE,3294
11
11
  pyqqq/backtest/positionprovider.py,sha256=wrR7Bntg28Q5_vGQV6XNzxe-SYoO9_GLcV9gDVEDAN4,4164
@@ -20,10 +20,10 @@ pyqqq/brokerage/ebest/simple.py,sha256=Ade3m18yhGt1fyn7ZbN-LmyNKiFP2ahUMSLLqMXWc
20
20
  pyqqq/brokerage/ebest/tr_client.py,sha256=6vtod4xXr35yMAIji5qXUr_C3Bf4C_1NDLgELohDuks,7914
21
21
  pyqqq/brokerage/helper.py,sha256=6pDiHo2eqsppC5ObIUMJibeMZ7cq8V9pVzNLTsdAy1w,6675
22
22
  pyqqq/brokerage/kis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- pyqqq/brokerage/kis/domestic_stock.py,sha256=XpJ0fAItmGmzYv3bZCgFHvH_dvAIhlnD1OeVojaFl9k,226565
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=t9vCnyeiVSHra2oYe8Gb3qFzxe2wWwrnJVCPNm6N-_0,40170
26
+ pyqqq/brokerage/kis/simple.py,sha256=P1n6T04iuyE2TOkL_ik7tOBiV3k1fPbPxIGwpYwHuVM,41106
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
@@ -33,12 +33,12 @@ pyqqq/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  pyqqq/data/daily.py,sha256=k4dSiXNnT_J3mo0j_6VDjkGezBieVpIaZT3W_M7EU1Y,8019
34
34
  pyqqq/data/domestic.py,sha256=2FOYxDGw2W7DGwY61p3uGFb4IWqWUKiNdR3RlewjkCU,30352
35
35
  pyqqq/data/index.py,sha256=d5b-8a7IXu7yNJWt1tIe1Mj83NW0ZnQq8nsj2Sl3Gx8,6988
36
- pyqqq/data/minutes.py,sha256=b-bqThP39t7V5io5dzI953bi1oWrUH3uie8GsFS7HUY,14727
36
+ pyqqq/data/minutes.py,sha256=rTPvJaUM1Vwgd2C3y1HjHuRWdfxN4VY0rxtLf4Tw-Rs,14719
37
37
  pyqqq/data/overseas.py,sha256=yx7tCZHW8AvjIbtrP4dqIeC6wseRSzbg5ag3dm6H0LY,1234
38
38
  pyqqq/data/realtime.py,sha256=GkZPBkom4ufKiLAbQ7zCqkYgSITN4Ir9THaDZEOEhyw,14972
39
39
  pyqqq/data/ticks.py,sha256=DXioiKBsGTzwXyvEH0lpm8t5g-1nHIOLKMXoSrE1Rko,4127
40
40
  pyqqq/data/us_stocks.py,sha256=jXR9dQEVigrwTLEpX1aX1_AQvOlBopW265gwx8Nq8OA,12959
41
- pyqqq/datatypes.py,sha256=KnanWzat6w5w0vNvKHsWt9VOBwf9gh0njdt36PJBgXc,8370
41
+ pyqqq/datatypes.py,sha256=JhsouFfSzAaK0p4FHIh0KZUuAeOzIDFBvfgYMp2-p20,8403
42
42
  pyqqq/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  pyqqq/executors/hook.py,sha256=xV9SVUpUwGm8AgEuz8aD7U4ema47lRoKn4KFthuLJwQ,36985
44
44
  pyqqq/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -58,6 +58,6 @@ pyqqq/utils/mock_api.py,sha256=7EsaVQ9mOVZQAqtQW24isPnk9QTbJII7x3guhFyEMAE,10569
58
58
  pyqqq/utils/position_classifier.py,sha256=EaomByAWM2lVuYow5OFdJNrN64Fpukhj-lhFkjYpjeo,14908
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.176.dist-info/METADATA,sha256=A9x6mnSPGdqXxO2rkMK3Anv_e3So73RK-rNi_H8DG0s,1664
62
- pyqqq-0.12.176.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
- pyqqq-0.12.176.dist-info/RECORD,,
61
+ pyqqq-0.12.178.dist-info/METADATA,sha256=UmHaJ05Hlvr3k37KKHRs5nFF9xYe6gvjLnMR1QwmhYE,1664
62
+ pyqqq-0.12.178.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
+ pyqqq-0.12.178.dist-info/RECORD,,