ksxt 0.0.7__py3-none-any.whl → 0.0.9__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.
- ksxt/__init__.py +3 -1
- ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/api/__init__.py +26 -0
- ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/api/auto/api_generator.py +54 -0
- ksxt/api/auto/bithumb.py +35 -0
- ksxt/api/auto/koreainvest.py +49 -0
- ksxt/api/auto/upbit.py +39 -0
- ksxt/api/bithumb.py +42 -0
- ksxt/api/koreainvest.py +40 -0
- ksxt/api/upbit.py +54 -0
- ksxt/async_/__init__.py +4 -0
- ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/async_/base/__init__.py +0 -0
- ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
- ksxt/async_/base/async_exchange.py +232 -0
- ksxt/async_/base/throttler.py +63 -0
- ksxt/async_/bithumb.py +455 -0
- ksxt/async_/koreainvest.py +849 -0
- ksxt/async_/upbit.py +488 -0
- ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
- ksxt/base/com_exchange.py +2 -2
- ksxt/base/errors.py +10 -0
- ksxt/base/exchange.py +188 -497
- ksxt/base/rest_exchange.py +297 -113
- ksxt/base/types.py +1 -36
- ksxt/bithumb.py +504 -0
- ksxt/config/__init__.py +2 -1
- ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/config/bithumb.toml +380 -0
- ksxt/config/koreainvest.toml +312 -0
- ksxt/config/token.toml +7 -0
- ksxt/config/upbit.toml +428 -0
- ksxt/koreainvest.py +409 -1055
- ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
- ksxt/market/base.py +50 -50
- ksxt/market/db.py +5 -4
- ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
- ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
- ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
- ksxt/market/krx/kosdaq.py +150 -147
- ksxt/market/krx/kospi.py +179 -175
- ksxt/market/krx/stock.py +136 -134
- ksxt/market/logging.py +4 -4
- ksxt/market/manager.py +11 -13
- ksxt/market/markets.py +1 -1
- ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
- ksxt/market/us/amex.py +31 -31
- ksxt/market/us/nasdaq.py +31 -31
- ksxt/market/us/nyse.py +31 -31
- ksxt/market/us/stock.py +20 -28
- ksxt/models/__init__.py +16 -0
- ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
- ksxt/models/balance.py +30 -0
- ksxt/models/cash.py +15 -0
- ksxt/models/common.py +31 -0
- ksxt/models/error.py +13 -0
- ksxt/models/historical.py +26 -0
- ksxt/models/market.py +81 -0
- ksxt/models/order.py +42 -0
- ksxt/models/orderbook.py +32 -0
- ksxt/models/ticker.py +25 -0
- ksxt/models/token.py +14 -0
- ksxt/models/transaction.py +79 -0
- ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/parser/bithumb.py +300 -0
- ksxt/parser/koreainvest.py +323 -0
- ksxt/parser/parser.py +114 -0
- ksxt/parser/upbit.py +308 -0
- ksxt/upbit.py +499 -0
- ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
- ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
- ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
- ksxt/utils/safer.py +48 -0
- ksxt/utils/sorter.py +8 -0
- ksxt/utils/timer.py +47 -0
- {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/METADATA +11 -1
- ksxt-0.0.9.dist-info/RECORD +119 -0
- {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/WHEEL +1 -1
- ksxt/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/__pycache__/koreainvest.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/exchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/restexchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/types.cpython-39.pyc +0 -0
- ksxt/base/api_response.py +0 -68
- ksxt/config/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/config/tr_app.json +0 -381
- ksxt/config/tr_dev.json +0 -446
- ksxt/market/__pycache__/base.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/db.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/logging.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/manager.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/markets.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/kosdaq.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/kospi.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/stock.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/amex.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/nasdaq.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/nyse.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/stock.cpython-39.pyc +0 -0
- ksxt-0.0.7.dist-info/RECORD +0 -49
- {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/LICENSE.txt +0 -0
- {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/top_level.txt +0 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
ksxt/market/base.py
CHANGED
@@ -15,11 +15,12 @@ from ksxt.market.logging import KsxtLogger
|
|
15
15
|
if TYPE_CHECKING:
|
16
16
|
from ksxt.market.manager import MarketManager
|
17
17
|
|
18
|
+
|
18
19
|
class MarketItemBase:
|
19
|
-
|
20
|
-
|
20
|
+
"""시장 종목"""
|
21
|
+
|
21
22
|
def __init__(self, data: str, delimiter: Optional[str] = None):
|
22
|
-
items = self.__class__.__dict__[
|
23
|
+
items = self.__class__.__dict__["CONTROL"].copy()
|
23
24
|
data_len = len(data)
|
24
25
|
index = 0
|
25
26
|
reverse = False
|
@@ -30,17 +31,17 @@ class MarketItemBase:
|
|
30
31
|
while items:
|
31
32
|
key, value = items[0]
|
32
33
|
del items[0]
|
33
|
-
|
34
|
-
if key ==
|
34
|
+
|
35
|
+
if key == "_reverse":
|
35
36
|
items.reverse()
|
36
37
|
reverse = not reverse
|
37
38
|
continue
|
38
|
-
elif key ==
|
39
|
+
elif key == "_index":
|
39
40
|
if value < 0:
|
40
41
|
value = data_len - (abs(value) - 1)
|
41
42
|
index = value
|
42
43
|
continue
|
43
|
-
elif key[:2] ==
|
44
|
+
elif key[:2] == "__":
|
44
45
|
continue
|
45
46
|
elif isinstance(value, tuple):
|
46
47
|
value = list(value)
|
@@ -49,22 +50,21 @@ class MarketItemBase:
|
|
49
50
|
if v < 0:
|
50
51
|
value[i] = data_len - abs(v)
|
51
52
|
|
52
|
-
v = data[value[0]:value[1]]
|
53
|
+
v = data[value[0] : value[1]]
|
53
54
|
elif reverse:
|
54
|
-
v = data[index - value:index]
|
55
|
+
v = data[index - value : index]
|
55
56
|
index -= value
|
56
57
|
else:
|
57
58
|
if delimiter is None:
|
58
|
-
v = data[index:index + value]
|
59
|
+
v = data[index : index + value]
|
59
60
|
index += value
|
60
61
|
else:
|
61
62
|
v = splitted[index]
|
62
63
|
index += 1
|
63
|
-
|
64
64
|
|
65
|
-
if key ==
|
65
|
+
if key == "_dummy":
|
66
66
|
continue
|
67
|
-
|
67
|
+
|
68
68
|
type = self.__annotations__[key]
|
69
69
|
setattr(self, key, self.__convert(type, v.strip()))
|
70
70
|
|
@@ -72,10 +72,10 @@ class MarketItemBase:
|
|
72
72
|
try:
|
73
73
|
if type != str:
|
74
74
|
if type == bool:
|
75
|
-
return value ==
|
75
|
+
return value == "Y" if value else None
|
76
76
|
elif type == datetime:
|
77
|
-
return datetime.strptime(value,
|
78
|
-
elif type.__name__ ==
|
77
|
+
return datetime.strptime(value, "%Y%m%d")
|
78
|
+
elif type.__name__ == "Literal":
|
79
79
|
return value
|
80
80
|
|
81
81
|
return type(value)
|
@@ -84,20 +84,20 @@ class MarketItemBase:
|
|
84
84
|
return value
|
85
85
|
|
86
86
|
|
87
|
-
t_item = TypeVar(
|
88
|
-
t_dbitem = TypeVar(
|
87
|
+
t_item = TypeVar("t_item", bound=MarketItemBase)
|
88
|
+
t_dbitem = TypeVar("t_dbitem", bound=Base)
|
89
89
|
|
90
90
|
|
91
91
|
class MarketBase(Generic[t_item, t_dbitem], KsxtLogger):
|
92
|
-
manager:
|
92
|
+
manager: "MarketManager"
|
93
93
|
code: str
|
94
94
|
name: str
|
95
95
|
mst: str
|
96
|
-
encoding: str =
|
96
|
+
encoding: str = "cp949"
|
97
97
|
|
98
98
|
_lock: Lock
|
99
|
-
|
100
|
-
def __init__(self, manager:
|
99
|
+
|
100
|
+
def __init__(self, manager: "MarketManager", code: str, name: str, mst: str):
|
101
101
|
self.manager = manager
|
102
102
|
self.code = code
|
103
103
|
self.name = name
|
@@ -105,71 +105,72 @@ class MarketBase(Generic[t_item, t_dbitem], KsxtLogger):
|
|
105
105
|
self._lock = Lock()
|
106
106
|
|
107
107
|
def sync(self, cache: bool = True):
|
108
|
-
|
108
|
+
"""종목 정보를 동기화합니다."""
|
109
109
|
with self._lock:
|
110
110
|
if cache:
|
111
111
|
sync_at = self.manager.sync_at(self.code)
|
112
112
|
|
113
113
|
if sync_at and datetime.now() - sync_at < timedelta(days=1):
|
114
|
-
self.manager.logger.info(f
|
114
|
+
self.manager.logger.info(f"MARKET: up to date {self.code}")
|
115
115
|
return
|
116
116
|
|
117
117
|
self._sync()
|
118
118
|
|
119
119
|
def _sync(self):
|
120
|
-
self.logger.info(f
|
120
|
+
self.logger.info(f"MARKET: sync {self.code}, download {self.mst}")
|
121
121
|
with zipfile.ZipFile(io.BytesIO(requests.get(self.mst).content)) as archive:
|
122
122
|
data = archive.read(archive.filelist[0])
|
123
123
|
self._update(data.decode(self.encoding))
|
124
|
-
|
124
|
+
|
125
125
|
def _update(self, data: str):
|
126
126
|
lines = data.splitlines()
|
127
|
-
self.logger.info(f
|
127
|
+
self.logger.info(f"MARKET: parsing {self.code} data... {len(lines)} lines")
|
128
128
|
type, db_type = get_args(self.__orig_bases__[0]) # type: ignore
|
129
129
|
|
130
130
|
with self.manager.session as ss:
|
131
131
|
for line in lines:
|
132
|
-
if not line:
|
132
|
+
if not line:
|
133
|
+
continue
|
133
134
|
item = db_type()
|
134
135
|
state = item._sa_instance_state
|
135
136
|
item.__dict__ = type(line).__dict__
|
136
137
|
item._sa_instance_state = state
|
137
138
|
ss.merge(item)
|
138
|
-
|
139
|
+
|
139
140
|
self.manager._update_sync_at(self.code)
|
140
141
|
ss.commit()
|
141
142
|
|
142
143
|
if self.logger.level == logging.DEBUG:
|
143
|
-
self.logger.info(f
|
144
|
-
|
144
|
+
self.logger.info(f"MARKET: up to date {self.code}, {ss.query(db_type).count()} items")
|
145
|
+
|
145
146
|
def _sf_acc(self):
|
146
147
|
with self._lock:
|
147
148
|
pass
|
148
149
|
|
149
150
|
def _market(self) -> Market:
|
150
|
-
return Market(
|
151
|
-
|
152
|
-
name=self.name
|
153
|
-
)
|
154
|
-
|
151
|
+
return Market(code=self.code, name=self.name)
|
152
|
+
|
155
153
|
@property
|
156
154
|
def _session(self) -> Session:
|
157
155
|
return self.manager.session
|
158
|
-
|
156
|
+
|
159
157
|
def _search(self, column: Column, name: str, limit: int = 50) -> Iterable:
|
160
158
|
self._sf_acc()
|
161
159
|
type, db_type = get_args(self.__orig_bases__[0]) # type: ignore
|
162
160
|
|
163
161
|
with self._session as sess:
|
164
162
|
keywords = name.split()
|
165
|
-
for item in
|
166
|
-
.
|
167
|
-
.
|
163
|
+
for item in (
|
164
|
+
sess.query(db_type)
|
165
|
+
.filter(and_(*[column.like(f"%{keyword}%") for keyword in keywords]))
|
166
|
+
.limit(limit)
|
167
|
+
.all()
|
168
|
+
):
|
168
169
|
data = type()
|
169
|
-
del item.__dict__[
|
170
|
+
del item.__dict__["_sa_instance_state"]
|
170
171
|
data.__dict__ = item.__dict__
|
171
172
|
yield data
|
172
|
-
|
173
|
+
|
173
174
|
def _get(self, column: Column, data: str) -> t_item:
|
174
175
|
self._sf_acc()
|
175
176
|
type, db_type = get_args(self.__orig_bases__[0]) # type: ignore
|
@@ -179,36 +180,35 @@ class MarketBase(Generic[t_item, t_dbitem], KsxtLogger):
|
|
179
180
|
|
180
181
|
if item:
|
181
182
|
data = type()
|
182
|
-
del item.__dict__[
|
183
|
+
del item.__dict__["_sa_instance_state"]
|
183
184
|
data.__dict__ = item.__dict__
|
184
185
|
return data # type: ignore
|
185
186
|
|
186
187
|
return None
|
187
188
|
|
188
189
|
def items(self, offset: int = 0, limit: int = 100) -> Iterable:
|
189
|
-
|
190
|
+
"""종목 정보를 반환합니다."""
|
190
191
|
self._sf_acc()
|
191
192
|
type, db_type = get_args(self.__orig_bases__[0]) # type: ignore
|
192
193
|
|
193
194
|
with self._session as sess:
|
194
195
|
for item in sess.query(db_type).offset(offset).limit(limit).all():
|
195
196
|
data = type()
|
196
|
-
del item.__dict__[
|
197
|
+
del item.__dict__["_sa_instance_state"]
|
197
198
|
data.__dict__ = item.__dict__
|
198
199
|
yield data
|
199
200
|
|
200
201
|
def all(self):
|
201
202
|
self._sf_acc()
|
202
203
|
return self.items(limit=999999)
|
203
|
-
|
204
|
+
|
204
205
|
@abstractmethod
|
205
206
|
def search(self, name: str, limit: int = 50) -> Iterable:
|
206
|
-
|
207
|
+
"""종목 이름으로 검색합니다."""
|
207
208
|
raise NotImplementedError()
|
208
|
-
|
209
|
+
|
209
210
|
def search_one(self, name: str) -> t_item:
|
210
211
|
for i in self.search(name, 1):
|
211
212
|
return i
|
212
|
-
|
213
|
+
|
213
214
|
return None
|
214
|
-
|
ksxt/market/db.py
CHANGED
@@ -3,14 +3,15 @@ from sqlalchemy.ext.declarative import declarative_base
|
|
3
3
|
|
4
4
|
Base = declarative_base()
|
5
5
|
|
6
|
+
|
6
7
|
class Market(Base):
|
7
|
-
__tablename__ =
|
8
|
+
__tablename__ = "market"
|
8
9
|
|
9
10
|
# Market Code
|
10
11
|
code = Column(String, primary_key=True)
|
11
|
-
|
12
|
+
|
12
13
|
# Market Name
|
13
14
|
name = Column(String, nullable=False)
|
14
|
-
|
15
|
+
|
15
16
|
# Sync time
|
16
|
-
sync_at = Column(DateTime, nullable=True)
|
17
|
+
sync_at = Column(DateTime, nullable=True)
|
Binary file
|
Binary file
|
Binary file
|