pyqqq 0.12.187__tar.gz → 0.12.189__tar.gz
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-0.12.187 → pyqqq-0.12.189}/PKG-INFO +1 -1
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyproject.toml +1 -1
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/broker.py +93 -28
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/domestic_stock.py +54 -17
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/simple.py +2 -1
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/daily.py +36 -24
- {pyqqq-0.12.187 → pyqqq-0.12.189}/README.md +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/environment.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/logger.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/positionprovider.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/strategy.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/utils.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/backtest/wallclock.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/ebest/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/ebest/domestic_stock.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/ebest/oauth.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/ebest/simple.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/ebest/tr_client.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/helper.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/oauth.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/overseas_stock.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/simple_overseas.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/kis/tr_client.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/multiprocess_tracker.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/brokerage/tracker.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/config.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/domestic.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/index.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/minutes.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/overseas.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/realtime.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/ticks.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/data/us_stocks.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/datatypes.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/executors/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/executors/hook.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/__init__.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/api_client.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/array.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/casting.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/compute.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/copycat.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/daily_tickers.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/display.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/kvstore.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/limiter.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/local_cache.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/logger.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/market_schedule.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/mock_api.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/position_classifier.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/retry.py +0 -0
- {pyqqq-0.12.187 → pyqqq-0.12.189}/pyqqq/utils/singleton.py +0 -0
|
@@ -287,8 +287,8 @@ class TradingBroker(BaseBroker):
|
|
|
287
287
|
if data_exchange == DataExchange.NXT and price_data.get("open_price", 0) == 0: # current_price는 어제의 값을 반환하므로 open_price가 0인지로 NXT 시장 여부 확인
|
|
288
288
|
price_data = self.data_api.get_price(code, data_exchange=DataExchange.KRX)
|
|
289
289
|
else:
|
|
290
|
-
if self.market_nxt_on:
|
|
291
|
-
price_data = self.data_api.get_price(code, data_exchange=DataExchange.
|
|
290
|
+
if self.market_nxt_on:
|
|
291
|
+
price_data = self.data_api.get_price(code, data_exchange=DataExchange.UN)
|
|
292
292
|
if price_data.get("open_price", 0) == 0: # current_price는 어제의 값을 반환하므로 open_price가 0인지로 NXT 시장 여부 확인
|
|
293
293
|
price_data = self.data_api.get_price(code, data_exchange=DataExchange.KRX)
|
|
294
294
|
else:
|
|
@@ -306,7 +306,7 @@ class TradingBroker(BaseBroker):
|
|
|
306
306
|
result = self.data_api.get_today_minute_data(code, data_exchange=DataExchange.KRX)
|
|
307
307
|
else:
|
|
308
308
|
if self.market_nxt_on:
|
|
309
|
-
result = self.data_api.get_today_minute_data(code, data_exchange=DataExchange.
|
|
309
|
+
result = self.data_api.get_today_minute_data(code, data_exchange=DataExchange.UN)
|
|
310
310
|
if result.empty or result.iloc[-1].close == 0:
|
|
311
311
|
result = self.data_api.get_today_minute_data(code, data_exchange=DataExchange.KRX)
|
|
312
312
|
else:
|
|
@@ -316,12 +316,12 @@ class TradingBroker(BaseBroker):
|
|
|
316
316
|
def get_daily_price(self, code: str, from_date: dtm.date, to_date: dtm.date, data_exchange: Optional[DataExchange] = None) -> pd.DataFrame:
|
|
317
317
|
if data_exchange:
|
|
318
318
|
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=data_exchange)
|
|
319
|
-
if data_exchange == DataExchange.NXT and result.empty:
|
|
319
|
+
if data_exchange == DataExchange.NXT and (result.empty or result.iloc[0].open == 0):
|
|
320
320
|
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.KRX)
|
|
321
321
|
else:
|
|
322
322
|
if self.market_nxt_on:
|
|
323
|
-
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.
|
|
324
|
-
if result.empty:
|
|
323
|
+
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.UN)
|
|
324
|
+
if result.empty or result.iloc[0].open == 0:
|
|
325
325
|
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.KRX)
|
|
326
326
|
else:
|
|
327
327
|
result = self.data_api.get_historical_daily_data(code, from_date, to_date, adjusted_price=True, data_exchange=DataExchange.KRX)
|
|
@@ -576,7 +576,12 @@ class MockBroker(BaseBroker):
|
|
|
576
576
|
market_schedule = get_market_schedule(today, exchange=self._get_exchange_code())
|
|
577
577
|
open_time = market_schedule.open_time
|
|
578
578
|
if self.market_nxt_on:
|
|
579
|
-
|
|
579
|
+
try:
|
|
580
|
+
nxt_market_schedule = get_market_schedule(today, exchange="NXT")
|
|
581
|
+
open_time = nxt_market_schedule.open_time
|
|
582
|
+
except ValueError:
|
|
583
|
+
# 2025-03-04 이전 날짜는 ValueError 이므로 무시
|
|
584
|
+
pass
|
|
580
585
|
|
|
581
586
|
if now.time() < open_time:
|
|
582
587
|
last_trading_day = get_last_trading_day(today, exchange=self._get_exchange_code())
|
|
@@ -603,7 +608,7 @@ class MockBroker(BaseBroker):
|
|
|
603
608
|
|
|
604
609
|
def get_minute_price(self, code: str) -> pd.DataFrame:
|
|
605
610
|
"""
|
|
606
|
-
self.clock 기준 당일의 정규장 시작부터 현재 시각 (이전) 까지의 분봉 데이터를 조회합니다.
|
|
611
|
+
self.clock 기준 당일의 정규장 시작부터 현재 시각 (이전) 까지의 분봉 데이터를 조회합니다.
|
|
607
612
|
단, market_nxt_on 이면, NXT 가능 종목의 경우 프리마켓, 정규마켓, 애프터마켓의 분봉을 모두 조회합니다.
|
|
608
613
|
|
|
609
614
|
Args:
|
|
@@ -623,10 +628,15 @@ class MockBroker(BaseBroker):
|
|
|
623
628
|
close_time = dtm.datetime.combine(today, market_schedule.close_time)
|
|
624
629
|
|
|
625
630
|
# TODO: us_stock 에 대해서는 따로 적용해야 함.
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
631
|
+
try:
|
|
632
|
+
nxt_market_schedule = get_market_schedule(today, "NXT")
|
|
633
|
+
is_nxt = df.index[0] == dtm.datetime.combine(today, nxt_market_schedule.open_time)
|
|
634
|
+
if self.market_nxt_on and is_nxt:
|
|
635
|
+
open_time = dtm.datetime.combine(today, nxt_market_schedule.open_time)
|
|
636
|
+
close_time = dtm.datetime.combine(today, nxt_market_schedule.close_time)
|
|
637
|
+
except ValueError:
|
|
638
|
+
# 2025-03-04 이전 날짜는 ValueError 이므로 무시
|
|
639
|
+
pass
|
|
630
640
|
|
|
631
641
|
if df.index.tz is not None:
|
|
632
642
|
df.index = df.index.tz_localize(None)
|
|
@@ -707,9 +717,40 @@ class MockBroker(BaseBroker):
|
|
|
707
717
|
dfs = get_us_minute_data(date, [code])
|
|
708
718
|
else:
|
|
709
719
|
if self.market_nxt_on:
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
720
|
+
# NXT 에 해당 종목이 없는 경우 KRX 의 결과값을 반환한다. 하지만 로컬 캐시 폴더는 NXT 기준으로 저장한다.
|
|
721
|
+
dfs = get_kr_minute_data(date, [code], dtm.timedelta(minutes=1), source="kis", adjusted=True, exchange=DataExchange.KRX)
|
|
722
|
+
dfs_nxt = get_kr_minute_data(date, [code], dtm.timedelta(minutes=1), source="kis", adjusted=True, exchange=DataExchange.NXT)
|
|
723
|
+
if code in dfs_nxt and not dfs_nxt[code].empty:
|
|
724
|
+
_df = dfs[code]
|
|
725
|
+
_df_nxt = dfs_nxt[code]
|
|
726
|
+
common_dates = _df.index.intersection(_df_nxt.index)
|
|
727
|
+
for _date in common_dates:
|
|
728
|
+
_df_nxt.loc[_date, 'volume'] = _df.loc[_date, 'volume'] + _df_nxt.loc[_date, 'volume']
|
|
729
|
+
_df_nxt.loc[_date, 'value'] = _df.loc[_date, 'value'] + _df_nxt.loc[_date, 'value']
|
|
730
|
+
_df_nxt.loc[_date, 'cum_volume'] = _df.loc[_date, 'cum_volume'] + _df_nxt.loc[_date, 'cum_volume']
|
|
731
|
+
_df_nxt.loc[_date, 'cum_value'] = _df.loc[_date, 'cum_value'] + _df_nxt.loc[_date, 'cum_value']
|
|
732
|
+
# 한투 앱에서 통합 차트의 경우 KRX값이 우선으로 사용됨
|
|
733
|
+
_df_nxt.loc[_date, 'open'] = _df.loc[_date, 'open']
|
|
734
|
+
_df_nxt.loc[_date, 'high'] = max(_df.loc[_date, 'high'], _df_nxt.loc[_date, 'high'])
|
|
735
|
+
_df_nxt.loc[_date, 'low'] = min(_df.loc[_date, 'low'], _df_nxt.loc[_date, 'low'])
|
|
736
|
+
_df_nxt.loc[_date, 'close'] = _df.loc[_date, 'close']
|
|
737
|
+
|
|
738
|
+
# 15:30 이후의 cum_volume, cum_value는 15:30의 cum_volume, cum_value에다가 _df_nxt의 15:31 부터 각 volume, value를 매분 누적하여 저장
|
|
739
|
+
market_close_datetime = dtm.datetime.combine(date, get_market_schedule(date, "KRX").close_time)
|
|
740
|
+
if market_close_datetime in _df_nxt.index:
|
|
741
|
+
base_cum_volume = _df_nxt.loc[market_close_datetime, 'cum_volume']
|
|
742
|
+
base_cum_value = _df_nxt.loc[market_close_datetime, 'cum_value']
|
|
743
|
+
|
|
744
|
+
# 15:31 이후 데이터에 대해 누적 계산
|
|
745
|
+
after_market_close = _df_nxt.index > market_close_datetime
|
|
746
|
+
if after_market_close.any():
|
|
747
|
+
for idx in _df_nxt[after_market_close].index:
|
|
748
|
+
_df_nxt.loc[idx, 'cum_volume'] = base_cum_volume + _df_nxt.loc[idx, 'volume']
|
|
749
|
+
_df_nxt.loc[idx, 'cum_value'] = base_cum_value + _df_nxt.loc[idx, 'value']
|
|
750
|
+
base_cum_volume = _df_nxt.loc[idx, 'cum_volume']
|
|
751
|
+
base_cum_value = _df_nxt.loc[idx, 'cum_value']
|
|
752
|
+
|
|
753
|
+
dfs[code] = _df_nxt
|
|
713
754
|
else:
|
|
714
755
|
dfs = get_kr_minute_data(date, [code], dtm.timedelta(minutes=1), source="kis", adjusted=True, exchange=DataExchange.KRX)
|
|
715
756
|
|
|
@@ -736,7 +777,7 @@ class MockBroker(BaseBroker):
|
|
|
736
777
|
|
|
737
778
|
def get_daily_price(self, code: str, from_date: Optional[dtm.date] = None, end_date: Optional[dtm.date] = None):
|
|
738
779
|
"""
|
|
739
|
-
지정된 기간 동안의 정규장 시작부터 현재 시각 (이전) 까지의 일봉 데이터를 조회합니다.
|
|
780
|
+
지정된 기간 동안의 정규장 시작부터 현재 시각 (이전) 까지의 일봉 데이터를 조회합니다.
|
|
740
781
|
단, market_nxt_on 이면, NXT 가능 종목의 경우 프리마켓, 정규마켓, 애프터마켓의 일봉을 모두 조회합니다.
|
|
741
782
|
"""
|
|
742
783
|
today = self.clock.today()
|
|
@@ -758,9 +799,18 @@ class MockBroker(BaseBroker):
|
|
|
758
799
|
dfs = get_us_daily_data([code], from_date, end_date, adjusted=True, ascending=True)
|
|
759
800
|
else:
|
|
760
801
|
if self.market_nxt_on:
|
|
761
|
-
dfs = get_kr_daily_data([code], from_date, end_date, adjusted=True, ascending=True, exchange=DataExchange.
|
|
762
|
-
|
|
763
|
-
|
|
802
|
+
dfs = get_kr_daily_data([code], from_date, end_date, adjusted=True, ascending=True, exchange=DataExchange.KRX)
|
|
803
|
+
dfs_nxt = get_kr_daily_data([code], from_date, end_date, adjusted=True, ascending=True, exchange=DataExchange.NXT)
|
|
804
|
+
if code in dfs_nxt:
|
|
805
|
+
_df = dfs[code]
|
|
806
|
+
_df_nxt = dfs_nxt[code]
|
|
807
|
+
|
|
808
|
+
# 같은 날짜의 데이터만 volume과 value를 합치고, open, close는 NXT 값으로 교체
|
|
809
|
+
common_dates = _df.index.intersection(_df_nxt.index)
|
|
810
|
+
for _date in common_dates:
|
|
811
|
+
_df.loc[_date, 'volume'] = _df.loc[_date, 'volume'] + _df_nxt.loc[_date, 'volume']
|
|
812
|
+
_df.loc[_date, 'value'] = _df.loc[_date, 'value'] + _df_nxt.loc[_date, 'value']
|
|
813
|
+
_df.loc[_date, 'open'] = _df_nxt.loc[_date, 'open']
|
|
764
814
|
else:
|
|
765
815
|
dfs = get_kr_daily_data([code], from_date, end_date, adjusted=True, ascending=True, exchange=DataExchange.KRX)
|
|
766
816
|
|
|
@@ -773,8 +823,13 @@ class MockBroker(BaseBroker):
|
|
|
773
823
|
open_time = schedule.open_time
|
|
774
824
|
close_time = schedule.close_time
|
|
775
825
|
if self.market_nxt_on:
|
|
776
|
-
|
|
777
|
-
|
|
826
|
+
try:
|
|
827
|
+
nxt_schedule = get_market_schedule(today, "NXT")
|
|
828
|
+
open_time = nxt_schedule.open_time
|
|
829
|
+
close_time = nxt_schedule.close_time
|
|
830
|
+
except ValueError:
|
|
831
|
+
# 2025-03-04 이전 날짜는 ValueError 이므로 무시
|
|
832
|
+
pass
|
|
778
833
|
|
|
779
834
|
if schedule.full_day_closed:
|
|
780
835
|
pass # end_date 가 폐장일이면 해당 날짜의 데이터는 이미 없음
|
|
@@ -933,18 +988,22 @@ class MockBroker(BaseBroker):
|
|
|
933
988
|
self.get_positions() # self.positions 에 있는 포지션들의 현재 가격을 조회하여 업데이트 함
|
|
934
989
|
|
|
935
990
|
today = current_time.date()
|
|
936
|
-
market_schedule = get_market_schedule(today)
|
|
991
|
+
market_schedule = get_market_schedule(today, exchange=Exchange.KRX)
|
|
937
992
|
|
|
938
993
|
open_time = dtm.datetime.combine(today, market_schedule.open_time)
|
|
939
994
|
close_time = dtm.datetime.combine(today, market_schedule.close_time)
|
|
940
995
|
preclose_auction_start_time = close_time - dtm.timedelta(minutes=10)
|
|
941
996
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
997
|
+
try:
|
|
998
|
+
nxt_market_schedule = get_market_schedule(today, exchange=Exchange.NXT)
|
|
999
|
+
except ValueError:
|
|
1000
|
+
nxt_market_schedule = market_schedule
|
|
1001
|
+
nxt_pre_open_time = dtm.datetime.combine(today, nxt_market_schedule.open_time)
|
|
1002
|
+
nxt_pre_close_time = nxt_pre_open_time + dtm.timedelta(minutes=50)
|
|
1003
|
+
# nxt_main_open_time = dtm.datetime.combine(today, open_time) + dtm.timedelta(seconds=30)
|
|
1004
|
+
# nxt_main_close_time = close_time - dtm.timedelta(minutes=10)
|
|
1005
|
+
nxt_after_open_time = close_time
|
|
1006
|
+
nxt_after_close_time = dtm.datetime.combine(today, nxt_market_schedule.close_time)
|
|
948
1007
|
|
|
949
1008
|
just_closed = current_time.replace(second=0, microsecond=0) == close_time.replace(second=0, microsecond=0)
|
|
950
1009
|
if preclose_auction_start_time - dtm.timedelta(minutes=1) <= current_time <= preclose_auction_start_time + dtm.timedelta(minutes=1):
|
|
@@ -971,6 +1030,10 @@ class MockBroker(BaseBroker):
|
|
|
971
1030
|
# 강제로 1분 차이를 만들어 줌
|
|
972
1031
|
before_time = current_time - dtm.timedelta(seconds=60)
|
|
973
1032
|
|
|
1033
|
+
if self.market_nxt_on and current_time < nxt_after_close_time and current_time - before_time < dtm.timedelta(seconds=60):
|
|
1034
|
+
# 강제로 1분 차이를 만들어 줌
|
|
1035
|
+
before_time = current_time - dtm.timedelta(seconds=60)
|
|
1036
|
+
|
|
974
1037
|
df = self.get_minute_price(order.asset_code)
|
|
975
1038
|
if df.empty:
|
|
976
1039
|
self.logger.warning(f"ORDER CANCELED: {order.asset_code} minute data is empty")
|
|
@@ -1278,6 +1341,7 @@ class MockBroker(BaseBroker):
|
|
|
1278
1341
|
d["market_cap"] = round(dft["value"].iloc[-1] / 100000000)
|
|
1279
1342
|
except Exception as e:
|
|
1280
1343
|
self.logger.error(f"get_market_cap error: {d['asset_code']} {d['name']} {prev_date} {e}")
|
|
1344
|
+
d["market_cap"] = 0
|
|
1281
1345
|
|
|
1282
1346
|
# 전일 거래대금
|
|
1283
1347
|
try:
|
|
@@ -1285,6 +1349,7 @@ class MockBroker(BaseBroker):
|
|
|
1285
1349
|
d["prev_value"] = round(dft["value"].iloc[-1] / 100000000)
|
|
1286
1350
|
except Exception as e:
|
|
1287
1351
|
self.logger.error(f"전일거래대금 error: {d['asset_code']} {d['name']} {prev_date} {e}")
|
|
1352
|
+
d["prev_value"] = 0
|
|
1288
1353
|
dict_list.append(d)
|
|
1289
1354
|
|
|
1290
1355
|
df = pd.DataFrame(dict_list)
|
|
@@ -122,6 +122,7 @@ class KISDomesticStock:
|
|
|
122
122
|
- mrkt_warn_cls_code: 시장경고코드 - 00:없음 01:투자주의 02:투자경고 03:투자위험
|
|
123
123
|
- short_over_yn: 단기과열여부 - Y/N
|
|
124
124
|
- sltr_yn: 정리매매여부 - Y/N
|
|
125
|
+
- mang_issu_cls_code: 관리종목여부 - Y/N
|
|
125
126
|
|
|
126
127
|
Raise:
|
|
127
128
|
ValueError: API 에러 발생시
|
|
@@ -666,7 +667,7 @@ class KISDomesticStock:
|
|
|
666
667
|
- per: PER
|
|
667
668
|
- eps: EPS
|
|
668
669
|
- pbr: PBR
|
|
669
|
-
- itewhol_loan_rmnd_ratem:
|
|
670
|
+
- itewhol_loan_rmnd_ratem: 전체 융자 잔고 비율
|
|
670
671
|
|
|
671
672
|
- output2: (list): 일별데이터
|
|
672
673
|
|
|
@@ -688,12 +689,23 @@ class KISDomesticStock:
|
|
|
688
689
|
| 06:권리중간배당락
|
|
689
690
|
| 07:권리분기배당락
|
|
690
691
|
|
|
691
|
-
- prtt_rate: 분할 비율
|
|
692
|
-
- mod_yn: 분할변경여부
|
|
692
|
+
- prtt_rate: 분할 비율 - 기준가/전일 종가
|
|
693
|
+
- mod_yn: 분할변경여부 - 현재 영업일에 체결이 발생하지 않아 시가가 없을경우 Y 로 표시(차트에서 사용)
|
|
693
694
|
- prdy_vrss_sign: 전일 대비 부호
|
|
694
695
|
- prdy_vrss: 전일 대비
|
|
695
696
|
- revl_issu_reas: 재평가사유코드
|
|
696
697
|
|
|
698
|
+
| 00:해당없음
|
|
699
|
+
| 01:회사분할
|
|
700
|
+
| 02:자본감소
|
|
701
|
+
| 03:장기간정지
|
|
702
|
+
| 04:초과분배
|
|
703
|
+
| 05:대규모배당
|
|
704
|
+
| 06:회사분할합병
|
|
705
|
+
| 07:ETN증권병합/분할
|
|
706
|
+
| 08:신종증권기세조정
|
|
707
|
+
| 99:기타
|
|
708
|
+
|
|
697
709
|
Raise:
|
|
698
710
|
ValueError: API 에러 발생시
|
|
699
711
|
"""
|
|
@@ -1603,7 +1615,7 @@ class KISDomesticStock:
|
|
|
1603
1615
|
|
|
1604
1616
|
return result
|
|
1605
1617
|
|
|
1606
|
-
def get_program_trade_by_stock(self, fid_input_iscd: str, tr_cont: str = ""):
|
|
1618
|
+
def get_program_trade_by_stock(self, fid_input_iscd: str, tr_cont: str = "", fid_cond_mrkt_div_code: str = "J"):
|
|
1607
1619
|
"""
|
|
1608
1620
|
(국내주식시세) 종목별 프로그램매매추이(체결)[v1_국내주식-044]
|
|
1609
1621
|
|
|
@@ -1614,6 +1626,7 @@ class KISDomesticStock:
|
|
|
1614
1626
|
Args:
|
|
1615
1627
|
fid_input_iscd (str): 입력 종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
|
|
1616
1628
|
tr_cont (str): 연속조회여부
|
|
1629
|
+
fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN NX:Nextrade UN:통합
|
|
1617
1630
|
|
|
1618
1631
|
Returns:
|
|
1619
1632
|
dict:
|
|
@@ -1647,7 +1660,10 @@ class KISDomesticStock:
|
|
|
1647
1660
|
url_path = "/uapi/domestic-stock/v1/quotations/program-trade-by-stock"
|
|
1648
1661
|
tr_id = "FHPPG04650101"
|
|
1649
1662
|
|
|
1650
|
-
params = {
|
|
1663
|
+
params = {
|
|
1664
|
+
"FID_INPUT_ISCD": fid_input_iscd,
|
|
1665
|
+
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
|
1666
|
+
}
|
|
1651
1667
|
|
|
1652
1668
|
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
|
|
1653
1669
|
if res_body["rt_cd"] != "0":
|
|
@@ -1674,7 +1690,17 @@ class KISDomesticStock:
|
|
|
1674
1690
|
|
|
1675
1691
|
return result
|
|
1676
1692
|
|
|
1677
|
-
def get_volume_rank(
|
|
1693
|
+
def get_volume_rank(
|
|
1694
|
+
self,
|
|
1695
|
+
fid_input_iscd: str,
|
|
1696
|
+
fid_div_cls_code: str,
|
|
1697
|
+
fid_blng_cls_code: str,
|
|
1698
|
+
fid_trgt_cls_code: str,
|
|
1699
|
+
fid_trgt_excls_cls_code: str,
|
|
1700
|
+
fid_input_price_1: int = None,
|
|
1701
|
+
fid_input_price_2: int = None,
|
|
1702
|
+
fid_vol_cnt: int = None,
|
|
1703
|
+
):
|
|
1678
1704
|
"""
|
|
1679
1705
|
(국내주식시세) 거래량순위[v1_국내주식-047]
|
|
1680
1706
|
|
|
@@ -2710,8 +2736,8 @@ class KISDomesticStock:
|
|
|
2710
2736
|
- fix_lblt (str): 고정부채
|
|
2711
2737
|
- total_lblt (str): 부채총계
|
|
2712
2738
|
- cpfn (str): 자본금
|
|
2713
|
-
- cfp_surp (str): 자본 잉여금
|
|
2714
|
-
- prfi_surp (str): 이익 잉여금
|
|
2739
|
+
- cfp_surp (str): 자본 잉여금 - 출력되지 않는 데이터(99.99로 표시)
|
|
2740
|
+
- prfi_surp (str): 이익 잉여금 - 출력되지 않는 데이터(99.99로 표시)
|
|
2715
2741
|
- total_cptl (str): 자본총계
|
|
2716
2742
|
|
|
2717
2743
|
Raise:
|
|
@@ -2874,8 +2900,11 @@ class KISDomesticStock:
|
|
|
2874
2900
|
Args:
|
|
2875
2901
|
gb1 (str): 조회구분 - 0: 배당전체, 1: 결산배당, 2: 중간배당
|
|
2876
2902
|
f_dt (str): 조회일자From - 일자 ~
|
|
2877
|
-
t_dt (str):
|
|
2903
|
+
t_dt (str): 조회일자To - ~ 일자
|
|
2878
2904
|
sht_cd (str): 종목코드 - 공백: 전체, 특정종목 조회시 : 종목코드
|
|
2905
|
+
high_gb (str): 고배당여부 - 공백
|
|
2906
|
+
cts (str): CTS - 공백
|
|
2907
|
+
|
|
2879
2908
|
|
|
2880
2909
|
Returns:
|
|
2881
2910
|
dict:
|
|
@@ -3222,14 +3251,14 @@ class KISDomesticStock:
|
|
|
3222
3251
|
|
|
3223
3252
|
| - 신용매수
|
|
3224
3253
|
| - 21:자기융자신규
|
|
3225
|
-
| - 23
|
|
3226
|
-
| - 26
|
|
3254
|
+
| - 23:유통융자신규
|
|
3255
|
+
| - 26:유통대주상환
|
|
3227
3256
|
| - 28:자기대주상환
|
|
3228
3257
|
| - 신용매도
|
|
3229
|
-
| -
|
|
3230
|
-
| - 27:유동융자상환
|
|
3231
|
-
| - 22:유동대주신규
|
|
3258
|
+
| - 22:유통대주신규
|
|
3232
3259
|
| - 24:자기대주신규
|
|
3260
|
+
| - 25:자기융자상환
|
|
3261
|
+
| - 27:유통융자상환
|
|
3233
3262
|
|
|
3234
3263
|
load_dt (dtm.date): 대출일자
|
|
3235
3264
|
|
|
@@ -3477,7 +3506,7 @@ class KISDomesticStock:
|
|
|
3477
3506
|
self,
|
|
3478
3507
|
cano: str,
|
|
3479
3508
|
acnt_prdt_cd: str,
|
|
3480
|
-
inqr_dvsn_1: str = "
|
|
3509
|
+
inqr_dvsn_1: str = "0",
|
|
3481
3510
|
inqr_dvsn_2: str = "0",
|
|
3482
3511
|
ctx_area_fk100: str = "",
|
|
3483
3512
|
ctx_area_nk100: str = "",
|
|
@@ -3490,7 +3519,7 @@ class KISDomesticStock:
|
|
|
3490
3519
|
Args:
|
|
3491
3520
|
cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
|
|
3492
3521
|
acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
|
|
3493
|
-
inqr_dvsn_1 (str): 조회구분1 - 0
|
|
3522
|
+
inqr_dvsn_1 (str): 조회구분1 - 0:주문 1:종목
|
|
3494
3523
|
inqr_dvsn_2 (str): 조회구분2 - 0:전체 1:매도 2:매수
|
|
3495
3524
|
ctx_area_fk100 (str): CTX_AREA_FK100
|
|
3496
3525
|
ctx_area_nk100 (str): CTX_AREA_NK100
|
|
@@ -3659,8 +3688,9 @@ class KISDomesticStock:
|
|
|
3659
3688
|
sll_buy_dvsn_cd (str): 매도매수구분코드 - 00:전체 01:매도 02:매수
|
|
3660
3689
|
inqr_dvsn (str): 조회구분 - 00:역순 01:정순
|
|
3661
3690
|
pdno (str): 상품번호 - 종목번호(6자리) 공란:전체 조회
|
|
3691
|
+
odno (str): 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호
|
|
3662
3692
|
ccld_dvsn (str): 체결구분 - 00:전체 01:체결 02:미체결
|
|
3663
|
-
inqr_dvsn_3 (str): 조회구분3 - 00:전체 01:현금 02
|
|
3693
|
+
inqr_dvsn_3 (str): 조회구분3 - 00:전체 01:현금 02:신용 03:담보 04:대주 05:대여 06:자기융자신규/상환 07:유통융자신규/상환
|
|
3664
3694
|
inqr_dvsn_1 (str): 조회구분1 - 공란:전체 1:ELW 2:프리보드
|
|
3665
3695
|
ctx_area_fk100 (str): 연속조회검색조건100 - "":최초 조회시 이전 조회 ctx_area_fk100 값:다음페이지 조회시(2번째부터)
|
|
3666
3696
|
ctx_area_nk100 (str): 연속조회키100 - "":최초 조회시 이전 조회 ctx_area_nk100 값:다음페이지 조회시(2번째부터)
|
|
@@ -3697,6 +3727,7 @@ class KISDomesticStock:
|
|
|
3697
3727
|
- cncl_yn: 취소여부
|
|
3698
3728
|
- tot_ccld_amt: 총체결금액
|
|
3699
3729
|
- loan_dt: 대출일자
|
|
3730
|
+
- ordr_empno: 주문자사번
|
|
3700
3731
|
- ord_dvsn_cd: 주문구분코드
|
|
3701
3732
|
|
|
3702
3733
|
| 00:지정가
|
|
@@ -3720,6 +3751,9 @@ class KISDomesticStock:
|
|
|
3720
3751
|
- rmn_qty: 잔여수량
|
|
3721
3752
|
- rjct_qty: 거부수량
|
|
3722
3753
|
- ccld_cndt_name: 체결조건명
|
|
3754
|
+
- inqr_ip_addr: 조회IP주소
|
|
3755
|
+
- cpbc_ordp_ord_rcit_dvsn_cd: 전산주문표주문접수구분코드
|
|
3756
|
+
- cpbc_ordp_infm_mthd_dvsn_cd: 전산주문표통보방법구분코드
|
|
3723
3757
|
- infm_tmd: 통보시각 - ※ 실전투자계좌로는 해당값이 제공되지 않습니다.
|
|
3724
3758
|
- ctac_tlno: 연락전화번호
|
|
3725
3759
|
- prdt_type_cd: 상품유형코드 - 300:주식 301:선물옵션 302:채권 306:ELS
|
|
@@ -4644,6 +4678,9 @@ class KISDomesticStock:
|
|
|
4644
4678
|
|
|
4645
4679
|
한국투자 HTS(eFriend Plus) > [0856] 기간별 매매손익 화면 에서 "일별" 클릭 시의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
|
4646
4680
|
|
|
4681
|
+
Note:
|
|
4682
|
+
- 00:30 ~ 03:00 사이에는 조회 불가능합니다.
|
|
4683
|
+
|
|
4647
4684
|
Args:
|
|
4648
4685
|
acnt_prdt_cd (str): 계좌상품코드
|
|
4649
4686
|
cano (str): 종합계좌번호
|
|
@@ -1107,7 +1107,8 @@ class KISSimpleDomesticStock:
|
|
|
1107
1107
|
elif ord_exg_gb == "4":
|
|
1108
1108
|
exchange = OrderExchange.SOR
|
|
1109
1109
|
|
|
1110
|
-
|
|
1110
|
+
if account_no == f"{self.account_no}{self.account_product_code}":
|
|
1111
|
+
print(f"- rctf_cls={rctf_cls} acpt_yn={acpt_yn} cntg_yn={cntg_yn} accepted={accepted} executed={executed} rejected={rejected} status={event_type}")
|
|
1111
1112
|
|
|
1112
1113
|
return OrderEvent(
|
|
1113
1114
|
asset_code,
|
|
@@ -46,23 +46,26 @@ def get_all_ohlcv_for_date(
|
|
|
46
46
|
- close (int): 종가.
|
|
47
47
|
- volume (int): 거래량.
|
|
48
48
|
- value (int): 거래대금.
|
|
49
|
-
- diff (int): 종가 대비 전일 종가의 차이.
|
|
50
|
-
- diff_rate (float): 종가 대비 전일 종가의 변화율.
|
|
51
49
|
|
|
52
50
|
Raises:
|
|
53
51
|
HTTPError: API 요청이 실패했을 때 발생.
|
|
54
52
|
|
|
55
53
|
Examples:
|
|
56
|
-
>>> ohlcv_data = get_all_ohlcv_for_date(datetime.date(
|
|
54
|
+
>>> ohlcv_data = get_all_ohlcv_for_date(datetime.date(2025, 3, 4), exchange="KRX")
|
|
57
55
|
>>> print(ohlcv_data)
|
|
58
|
-
open high low close volume
|
|
56
|
+
open high low close volume value
|
|
59
57
|
code
|
|
60
|
-
000020
|
|
61
|
-
000040
|
|
62
|
-
000050
|
|
63
|
-
000070
|
|
64
|
-
000075
|
|
65
|
-
...
|
|
58
|
+
000020 6200 6220 6090 6130 41954 257785065
|
|
59
|
+
000040 422 422 393 400 135979 54618038
|
|
60
|
+
000050 6350 6350 6240 6290 9957 62588010
|
|
61
|
+
000070 59800 61100 59500 60400 32555 1957081250
|
|
62
|
+
000075 59000 59400 58300 59400 2600 151987900
|
|
63
|
+
... ... ... ... ... ... ...
|
|
64
|
+
950160 35500 39150 35500 38950 332462 12638215825
|
|
65
|
+
950170 4900 4955 4880 4900 24198 118688025
|
|
66
|
+
950190 7860 7920 7770 7860 21309 166408215
|
|
67
|
+
950200 3855 3855 3785 3800 23268 88458215
|
|
68
|
+
950220 996 996 945 954 440017 421451605
|
|
66
69
|
"""
|
|
67
70
|
if isinstance(date, datetime.datetime):
|
|
68
71
|
date = date.date()
|
|
@@ -89,10 +92,15 @@ def get_all_ohlcv_for_date(
|
|
|
89
92
|
return pd.DataFrame()
|
|
90
93
|
else:
|
|
91
94
|
df = pd.DataFrame(rows, columns=cols)
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
|
|
96
|
+
# NOTE 서버 응답에서 diff, diff_rate 가 제거될 예정
|
|
97
|
+
columns_to_drop = ["diff", "diff_rate", "date"]
|
|
98
|
+
df.drop(columns=[col for col in columns_to_drop if col in df.columns], inplace=True)
|
|
94
99
|
df.set_index("code", inplace=True)
|
|
95
100
|
|
|
101
|
+
df = df[["open", "high", "low", "close", "volume", "value"]]
|
|
102
|
+
df = df.astype({"open": int, "high": int, "low": int, "close": int, "volume": int, "value": int})
|
|
103
|
+
|
|
96
104
|
return df
|
|
97
105
|
|
|
98
106
|
|
|
@@ -133,25 +141,23 @@ def get_ohlcv_by_codes_for_period(
|
|
|
133
141
|
- close (int): 종가.
|
|
134
142
|
- volume (int): 거래량.
|
|
135
143
|
- value (int): 거래대금.
|
|
136
|
-
- diff (int): 종가 대비 전일 종가의 차이.
|
|
137
|
-
- diff_rate (float): 종가 대비 전일 종가의 변화율.
|
|
138
144
|
|
|
139
145
|
Raises:
|
|
140
146
|
HTTPError: API 요청이 실패했을 때 발생.
|
|
141
147
|
|
|
142
148
|
Examples:
|
|
143
|
-
>>> dfs = get_ohlcv_by_codes_for_period(['005930', '319640'], datetime.date(
|
|
149
|
+
>>> dfs = get_ohlcv_by_codes_for_period(['005930', '319640'], datetime.date(2025, 7, 28), datetime.date(2025, 7, 30))
|
|
144
150
|
>>> print(dfs)
|
|
145
|
-
{'319640': open high low close volume value
|
|
151
|
+
{'319640': open high low close volume value
|
|
146
152
|
date
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
'005930': open high low close volume value
|
|
153
|
+
2025-07-30 20860 20930 20840 20870 47431 990834244
|
|
154
|
+
2025-07-29 20795 20850 20765 20810 39627 824529926
|
|
155
|
+
2025-07-28 20900 20985 20880 20965 26610 556764707,
|
|
156
|
+
'005930': open high low close volume value
|
|
151
157
|
date
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
2025-07-30 71000 73700 70600 72600 34761444 2521446314798
|
|
159
|
+
2025-07-29 70800 70800 68800 70600 28190940 1977721049950
|
|
160
|
+
2025-07-28 68200 70400 67200 70400 35332500 2431396606750}
|
|
155
161
|
"""
|
|
156
162
|
exchange = DataExchange.validate(exchange)
|
|
157
163
|
tz = pytz.timezone("Asia/Seoul")
|
|
@@ -192,8 +198,14 @@ def get_ohlcv_by_codes_for_period(
|
|
|
192
198
|
rows.reverse()
|
|
193
199
|
|
|
194
200
|
df = pd.DataFrame(rows, columns=cols)
|
|
195
|
-
|
|
201
|
+
|
|
202
|
+
# NOTE 서버 응답에서 diff, diff_rate 가 제거될 예정
|
|
203
|
+
columns_to_drop = ["diff", "diff_rate"]
|
|
204
|
+
df.drop(columns=[col for col in columns_to_drop if col in df.columns], inplace=True)
|
|
196
205
|
df.set_index("date", inplace=True)
|
|
206
|
+
|
|
207
|
+
df = df[["open", "high", "low", "close", "volume", "value"]]
|
|
208
|
+
df = df.astype({"open": int, "high": int, "low": int, "close": int, "volume": int, "value": int})
|
|
197
209
|
df.sort_index(ascending=ascending, inplace=True)
|
|
198
210
|
result[code] = df
|
|
199
211
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|