pyqqq 0.12.194__tar.gz → 0.12.196__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.194 → pyqqq-0.12.196}/PKG-INFO +1 -1
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyproject.toml +1 -1
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/broker.py +11 -2
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/tr_client.py +7 -6
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/domestic.py +2 -1
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/compute.py +2 -2
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/retry.py +4 -2
- {pyqqq-0.12.194 → pyqqq-0.12.196}/README.md +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/environment.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/logger.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/positionprovider.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/strategy.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/utils.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/backtest/wallclock.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/ebest/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/ebest/domestic_stock.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/ebest/oauth.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/ebest/simple.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/ebest/tr_client.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/helper.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/domestic_stock.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/oauth.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/overseas_stock.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/simple.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/kis/simple_overseas.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/multiprocess_tracker.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/brokerage/tracker.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/config.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/daily.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/index.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/minutes.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/overseas.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/realtime.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/ticks.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/data/us_stocks.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/datatypes.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/executors/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/executors/hook.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/__init__.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/api_client.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/array.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/casting.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/copycat.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/daily_tickers.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/display.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/kvstore.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/limiter.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/local_cache.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/logger.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/market_schedule.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/mock_api.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/position_classifier.py +0 -0
- {pyqqq-0.12.194 → pyqqq-0.12.196}/pyqqq/utils/singleton.py +0 -0
|
@@ -597,11 +597,17 @@ class MockBroker(BaseBroker):
|
|
|
597
597
|
# 현재 시간 데이터가 없을 경우 전일 종가로 대체
|
|
598
598
|
last_trading_day = get_last_trading_day(today, exchange=self._get_exchange_code())
|
|
599
599
|
df = self.get_daily_price(code, last_trading_day, last_trading_day) # 전일 종가는 일봉, 분봉 구분이 필요 없다.
|
|
600
|
-
|
|
600
|
+
if not df.empty:
|
|
601
|
+
return typed_result(df["close"].iloc[-1])
|
|
602
|
+
else:
|
|
603
|
+
return Decimal(0)
|
|
601
604
|
|
|
602
605
|
elif self.time_unit == "days":
|
|
603
606
|
df = self.get_daily_price(code, today, today)
|
|
604
|
-
|
|
607
|
+
if not df.empty:
|
|
608
|
+
return typed_result(df["close"].iloc[-1])
|
|
609
|
+
else:
|
|
610
|
+
return Decimal(0)
|
|
605
611
|
|
|
606
612
|
else:
|
|
607
613
|
raise ValueError(f"Invalid time unit: {self.time_unit}")
|
|
@@ -814,6 +820,9 @@ class MockBroker(BaseBroker):
|
|
|
814
820
|
else:
|
|
815
821
|
dfs = get_kr_daily_data([code], from_date, end_date, adjusted=True, ascending=True, exchange=DataExchange.KRX)
|
|
816
822
|
|
|
823
|
+
if code not in dfs:
|
|
824
|
+
return pd.DataFrame()
|
|
825
|
+
|
|
817
826
|
df = dfs[code]
|
|
818
827
|
|
|
819
828
|
if not df.empty and end_date == today:
|
|
@@ -25,7 +25,7 @@ class KISTRClient:
|
|
|
25
25
|
self.corp_data = corp_data
|
|
26
26
|
self.session = requests.Session()
|
|
27
27
|
|
|
28
|
-
@retry(requests.
|
|
28
|
+
@retry(requests.RequestException)
|
|
29
29
|
def request(self, path: str, tr_id: str, tr_cont: str = "", params: dict = None, body: dict = None, method: str = "GET"):
|
|
30
30
|
"""
|
|
31
31
|
TR 요청을 보내고 응답을 받는 메서드
|
|
@@ -132,21 +132,22 @@ class KISTRWebsocketClient:
|
|
|
132
132
|
yield data
|
|
133
133
|
|
|
134
134
|
except websockets.exceptions.ConnectionClosedError:
|
|
135
|
-
|
|
135
|
+
self.logger.error(f"{self.session_id}: ConnectionClosedError")
|
|
136
136
|
await asyncio.sleep(0.5)
|
|
137
137
|
continue
|
|
138
138
|
|
|
139
139
|
except ConnectionRefusedError:
|
|
140
|
+
self.logger.error(f"{self.session_id}: ConnectionRefusedError")
|
|
140
141
|
await asyncio.sleep(0.5)
|
|
141
142
|
continue
|
|
142
143
|
|
|
143
|
-
except websockets.ConnectionClosed
|
|
144
|
+
except websockets.ConnectionClosed:
|
|
145
|
+
self.logger.error(f"{self.session_id}: ConnectionClosed")
|
|
144
146
|
await asyncio.sleep(0.5)
|
|
145
|
-
self.logger.exception(e)
|
|
146
147
|
continue
|
|
147
148
|
|
|
148
|
-
except ssl.SSLZeroReturnError
|
|
149
|
-
self.logger.
|
|
149
|
+
except ssl.SSLZeroReturnError:
|
|
150
|
+
self.logger.error(f"{self.session_id}: SSLZeroReturnError")
|
|
150
151
|
await asyncio.sleep(0.5)
|
|
151
152
|
continue
|
|
152
153
|
|
|
@@ -229,7 +229,8 @@ def _isoformat_to_readable(isodate: str) -> str:
|
|
|
229
229
|
return ""
|
|
230
230
|
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
# _get_tickers가 메모이제이션 되어있어서 해당 함수는 캐싱하면 안됨
|
|
233
|
+
# 특히 date가 None으로 쓰는경우가 많은데 캐싱하면 오작동함
|
|
233
234
|
def get_tickers(
|
|
234
235
|
date: Optional[dtm.date] = None,
|
|
235
236
|
market: Optional[str] = None,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
from decimal import ROUND_CEILING, ROUND_FLOOR, ROUND_HALF_UP, Decimal
|
|
3
|
-
from typing import Union
|
|
3
|
+
from typing import Union, Optional
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def quantize_krx_price(price: Union[Decimal, int, float], etf_etn: bool, rounding: str = "floor") -> int:
|
|
@@ -50,7 +50,7 @@ def get_krx_tick_size(
|
|
|
50
50
|
price: float,
|
|
51
51
|
etf_etn: bool,
|
|
52
52
|
market: str = "KOSPI",
|
|
53
|
-
date: datetime.date = None,
|
|
53
|
+
date: Optional[datetime.date] = None,
|
|
54
54
|
) -> int:
|
|
55
55
|
"""
|
|
56
56
|
주어진 가격과 금융 상품 유형에 따라 적절한 호가가격단위를 반환합니다.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import time
|
|
2
2
|
from functools import wraps
|
|
3
|
+
from pyqqq.utils.logger import get_logger
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
def retry(exceptions, total_tries=5, delay=0.5, backoff=2, silently: bool = False):
|
|
@@ -28,6 +29,7 @@ def retry(exceptions, total_tries=5, delay=0.5, backoff=2, silently: bool = Fals
|
|
|
28
29
|
def decorator(func):
|
|
29
30
|
@wraps(func)
|
|
30
31
|
def wrapper(*args, **kwargs):
|
|
32
|
+
logger = get_logger(f"{__name__}.{func.__name__}")
|
|
31
33
|
current_try = 0
|
|
32
34
|
while current_try < total_tries:
|
|
33
35
|
try:
|
|
@@ -37,10 +39,10 @@ def retry(exceptions, total_tries=5, delay=0.5, backoff=2, silently: bool = Fals
|
|
|
37
39
|
sleep_time = delay * (backoff ** (current_try - 1))
|
|
38
40
|
if current_try != total_tries:
|
|
39
41
|
if not silently:
|
|
40
|
-
|
|
42
|
+
logger.warning(f"{str(e)}\nRetrying in {sleep_time} seconds...")
|
|
41
43
|
time.sleep(sleep_time)
|
|
42
44
|
else:
|
|
43
|
-
|
|
45
|
+
logger.error("Max retry attempts reached, aborting.")
|
|
44
46
|
raise
|
|
45
47
|
return wrapper
|
|
46
48
|
return decorator
|
|
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
|