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.
Files changed (141) hide show
  1. ksxt/__init__.py +3 -1
  2. ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
  3. ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
  4. ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
  5. ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
  6. ksxt/api/__init__.py +26 -0
  7. ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
  8. ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
  9. ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
  10. ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
  11. ksxt/api/auto/api_generator.py +54 -0
  12. ksxt/api/auto/bithumb.py +35 -0
  13. ksxt/api/auto/koreainvest.py +49 -0
  14. ksxt/api/auto/upbit.py +39 -0
  15. ksxt/api/bithumb.py +42 -0
  16. ksxt/api/koreainvest.py +40 -0
  17. ksxt/api/upbit.py +54 -0
  18. ksxt/async_/__init__.py +4 -0
  19. ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
  20. ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
  21. ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
  22. ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
  23. ksxt/async_/base/__init__.py +0 -0
  24. ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
  25. ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
  26. ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
  27. ksxt/async_/base/async_exchange.py +232 -0
  28. ksxt/async_/base/throttler.py +63 -0
  29. ksxt/async_/bithumb.py +455 -0
  30. ksxt/async_/koreainvest.py +849 -0
  31. ksxt/async_/upbit.py +488 -0
  32. ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
  33. ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
  34. ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
  35. ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
  36. ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
  37. ksxt/base/com_exchange.py +2 -2
  38. ksxt/base/errors.py +10 -0
  39. ksxt/base/exchange.py +188 -497
  40. ksxt/base/rest_exchange.py +297 -113
  41. ksxt/base/types.py +1 -36
  42. ksxt/bithumb.py +504 -0
  43. ksxt/config/__init__.py +2 -1
  44. ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
  45. ksxt/config/bithumb.toml +380 -0
  46. ksxt/config/koreainvest.toml +312 -0
  47. ksxt/config/token.toml +7 -0
  48. ksxt/config/upbit.toml +428 -0
  49. ksxt/koreainvest.py +409 -1055
  50. ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
  51. ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
  52. ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
  53. ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
  54. ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
  55. ksxt/market/base.py +50 -50
  56. ksxt/market/db.py +5 -4
  57. ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
  58. ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
  59. ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
  60. ksxt/market/krx/kosdaq.py +150 -147
  61. ksxt/market/krx/kospi.py +179 -175
  62. ksxt/market/krx/stock.py +136 -134
  63. ksxt/market/logging.py +4 -4
  64. ksxt/market/manager.py +11 -13
  65. ksxt/market/markets.py +1 -1
  66. ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
  67. ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
  68. ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
  69. ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
  70. ksxt/market/us/amex.py +31 -31
  71. ksxt/market/us/nasdaq.py +31 -31
  72. ksxt/market/us/nyse.py +31 -31
  73. ksxt/market/us/stock.py +20 -28
  74. ksxt/models/__init__.py +16 -0
  75. ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
  76. ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
  77. ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
  78. ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
  79. ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
  80. ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
  81. ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
  82. ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
  83. ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
  84. ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
  85. ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
  86. ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
  87. ksxt/models/balance.py +30 -0
  88. ksxt/models/cash.py +15 -0
  89. ksxt/models/common.py +31 -0
  90. ksxt/models/error.py +13 -0
  91. ksxt/models/historical.py +26 -0
  92. ksxt/models/market.py +81 -0
  93. ksxt/models/order.py +42 -0
  94. ksxt/models/orderbook.py +32 -0
  95. ksxt/models/ticker.py +25 -0
  96. ksxt/models/token.py +14 -0
  97. ksxt/models/transaction.py +79 -0
  98. ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
  99. ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
  100. ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
  101. ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
  102. ksxt/parser/bithumb.py +300 -0
  103. ksxt/parser/koreainvest.py +323 -0
  104. ksxt/parser/parser.py +114 -0
  105. ksxt/parser/upbit.py +308 -0
  106. ksxt/upbit.py +499 -0
  107. ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
  108. ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
  109. ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
  110. ksxt/utils/safer.py +48 -0
  111. ksxt/utils/sorter.py +8 -0
  112. ksxt/utils/timer.py +47 -0
  113. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/METADATA +11 -1
  114. ksxt-0.0.9.dist-info/RECORD +119 -0
  115. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/WHEEL +1 -1
  116. ksxt/__pycache__/__init__.cpython-39.pyc +0 -0
  117. ksxt/__pycache__/koreainvest.cpython-39.pyc +0 -0
  118. ksxt/base/__pycache__/__init__.cpython-39.pyc +0 -0
  119. ksxt/base/__pycache__/exchange.cpython-39.pyc +0 -0
  120. ksxt/base/__pycache__/rest_exchange.cpython-39.pyc +0 -0
  121. ksxt/base/__pycache__/restexchange.cpython-39.pyc +0 -0
  122. ksxt/base/__pycache__/types.cpython-39.pyc +0 -0
  123. ksxt/base/api_response.py +0 -68
  124. ksxt/config/__pycache__/__init__.cpython-39.pyc +0 -0
  125. ksxt/config/tr_app.json +0 -381
  126. ksxt/config/tr_dev.json +0 -446
  127. ksxt/market/__pycache__/base.cpython-39.pyc +0 -0
  128. ksxt/market/__pycache__/db.cpython-39.pyc +0 -0
  129. ksxt/market/__pycache__/logging.cpython-39.pyc +0 -0
  130. ksxt/market/__pycache__/manager.cpython-39.pyc +0 -0
  131. ksxt/market/__pycache__/markets.cpython-39.pyc +0 -0
  132. ksxt/market/krx/__pycache__/kosdaq.cpython-39.pyc +0 -0
  133. ksxt/market/krx/__pycache__/kospi.cpython-39.pyc +0 -0
  134. ksxt/market/krx/__pycache__/stock.cpython-39.pyc +0 -0
  135. ksxt/market/us/__pycache__/amex.cpython-39.pyc +0 -0
  136. ksxt/market/us/__pycache__/nasdaq.cpython-39.pyc +0 -0
  137. ksxt/market/us/__pycache__/nyse.cpython-39.pyc +0 -0
  138. ksxt/market/us/__pycache__/stock.cpython-39.pyc +0 -0
  139. ksxt-0.0.7.dist-info/RECORD +0 -49
  140. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/LICENSE.txt +0 -0
  141. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/top_level.txt +0 -0
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__['CONTROL'].copy()
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 == '_reverse':
34
+
35
+ if key == "_reverse":
35
36
  items.reverse()
36
37
  reverse = not reverse
37
38
  continue
38
- elif key == '_index':
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 == '_dummy':
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 == 'Y' if value else None
75
+ return value == "Y" if value else None
76
76
  elif type == datetime:
77
- return datetime.strptime(value, '%Y%m%d')
78
- elif type.__name__ == 'Literal':
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('t_item', bound=MarketItemBase)
88
- t_dbitem = TypeVar('t_dbitem', bound=Base)
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: 'MarketManager'
92
+ manager: "MarketManager"
93
93
  code: str
94
94
  name: str
95
95
  mst: str
96
- encoding: str = 'cp949'
96
+ encoding: str = "cp949"
97
97
 
98
98
  _lock: Lock
99
-
100
- def __init__(self, manager: 'MarketManager', code: str, name: str, mst: str):
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'MARKET: up to date {self.code}')
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'MARKET: sync {self.code}, download {self.mst}')
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'MARKET: parsing {self.code} data... {len(lines)} lines')
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: continue
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'MARKET: up to date {self.code}, {ss.query(db_type).count()} items')
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
- code=self.code,
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 sess.query(db_type) \
166
- .filter(and_(*[column.like(f'%{keyword}%') for keyword in keywords])) \
167
- .limit(limit).all():
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__['_sa_instance_state']
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__['_sa_instance_state']
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__['_sa_instance_state']
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__ = 'market'
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)