ksxt 0.0.8__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 +10 -12
  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.8.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.8.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.8.dist-info/RECORD +0 -49
  140. {ksxt-0.0.8.dist-info → ksxt-0.0.9.dist-info}/LICENSE.txt +0 -0
  141. {ksxt-0.0.8.dist-info → ksxt-0.0.9.dist-info}/top_level.txt +0 -0
@@ -1,28 +1,41 @@
1
1
  import json
2
+ import logging
3
+ import toml
2
4
  import os
3
- from datetime import datetime
4
- from typing import Any, Dict, Optional
5
+ from pathlib import Path
5
6
 
7
+ from typing import Any, Dict, List, Literal, Optional
8
+
9
+ from datetime import datetime, UTC
10
+ import pytz
11
+ import time
12
+
13
+ from ksxt.base.errors import NotSupportedError
6
14
  from ksxt.base.exchange import Exchange
7
15
  from ksxt.config import CONFIG_DIR
16
+ import ksxt.models
8
17
 
9
18
 
10
19
  class RestExchange(Exchange):
11
20
  required_credentials = {
12
- 'open_key': True,
13
- 'secret_key': True,
14
- 'uid': False,
15
- 'login': False,
16
- 'password': False,
17
- 'token': False
21
+ "open_key": True,
22
+ "secret_key": True,
23
+ "uid": False,
24
+ "login": False,
25
+ "password": False,
26
+ "token": False,
18
27
  }
19
28
 
20
29
  headers = None
21
30
  token = None
22
31
  token_expired = None
23
- type = 'rest'
32
+ type = "rest"
24
33
 
25
- def __init__(self, config: Dict=None) -> None:
34
+ rate_limit = 2000 # milliseconds = seconds * 1000
35
+ lastRestRequestTimestamp = 0
36
+ timezone = pytz.timezone("UTC")
37
+
38
+ def __init__(self, config: Dict = None, filename: str = None) -> None:
26
39
  super().__init__()
27
40
 
28
41
  self.headers = dict() if self.headers is None else self.headers
@@ -30,33 +43,100 @@ class RestExchange(Exchange):
30
43
  if config is None:
31
44
  config = {}
32
45
 
33
- settings = self.deep_extend(self.describe(), config)
46
+ # settings = self.deep_extend(self.describe(), config)
47
+ # Exchange.set_attr(self, settings)
48
+
49
+ settings = self.deep_extend(config)
34
50
  Exchange.set_attr(self, settings)
35
51
 
36
- apis = self._get_api_from_file()
52
+ apis = self._get_api_from_file(filename)
37
53
  Exchange.set_attr(self, apis)
38
-
39
- self.set_token()
54
+
55
+ def __del__(self):
56
+ if self.session:
57
+ try:
58
+ self.session.close()
59
+ except Exception as e:
60
+ pass
61
+
62
+ def _get_api_from_file(self, filename: str):
63
+ if filename is None:
64
+ tr_config_filename = "tr_dev.json" if self.is_dev else "tr_app.json"
65
+ else:
66
+ tr_config_filename = filename
67
+
68
+ config_path = os.path.join(CONFIG_DIR, tr_config_filename)
69
+
70
+ if Path(tr_config_filename).suffix == ".json":
71
+ with open(
72
+ config_path,
73
+ encoding="utf-8",
74
+ ) as f:
75
+ c = json.load(f)
76
+ return {"apis": c[self.name]}
77
+
78
+ elif Path(tr_config_filename).suffix == ".toml":
79
+ with open(config_path, mode="r") as f:
80
+ c = toml.load(f)
81
+ return c
40
82
 
41
83
  def check_token(func):
42
84
  def wrapper(self, *args, **kwargs):
43
- import time
44
- if self.token_expired is None or time.strftime('%Y-%m-%d %H:%M:%S') >= self.token_expired:
45
- self.set_token()
85
+ if not self.is_valid_token():
86
+ self.create_token()
46
87
 
47
88
  return func(self, *args, **kwargs)
89
+
48
90
  return wrapper
49
91
 
50
- def _get_api_from_file(self):
51
- tr_config_filename = 'tr_dev.json' if self.is_dev else 'tr_app.json'
92
+ def is_valid_token(self) -> bool:
93
+ self.load_token()
94
+ if self.token_expired is None:
95
+ return False
52
96
 
53
- config_path = os.path.join(CONFIG_DIR, tr_config_filename)
97
+ return datetime.now(self.timezone) <= self.timezone.localize(self.token_expired)
98
+
99
+ def read_token(self):
100
+ try:
101
+ token_path = os.path.join(CONFIG_DIR, "token.toml")
102
+ with open(token_path, mode="r") as f:
103
+ c = toml.load(f)
104
+ return c
105
+ except Exception as e:
106
+ return {}
107
+
108
+ def load_token(self):
109
+ try:
110
+ data = self.read_token()
54
111
 
55
- with open(config_path, encoding='utf-8',) as f:
56
- c = json.load(f)
57
- return { 'apis': c[self.name] }
112
+ if self.open_key in data.keys():
113
+ self.token = data[self.open_key]["token"]
114
+ self.token_expired = data[self.open_key]["expired"]
115
+ except Exception as e:
116
+ pass
58
117
 
59
- def set_token(self):
118
+ def save_token(self, open_key, token, expired):
119
+ try:
120
+ logging.info("save token")
121
+ logging.info(open_key)
122
+ logging.info(token)
123
+ logging.info(expired)
124
+
125
+ data = self.read_token()
126
+ if open_key not in data:
127
+ data[open_key] = {}
128
+ data[open_key]["token"] = token
129
+ data[open_key]["expired"] = expired
130
+
131
+ token_path = os.path.join(CONFIG_DIR, "token.toml")
132
+ with open(token_path, "w") as file:
133
+ toml.dump(data, file)
134
+
135
+ self.load_token()
136
+ except Exception as e:
137
+ pass
138
+
139
+ def create_token(self):
60
140
  pass
61
141
 
62
142
  def prepare_request_headers(self, headers=None):
@@ -67,18 +147,23 @@ class RestExchange(Exchange):
67
147
 
68
148
  self.headers.update(headers)
69
149
 
70
- headers.update({"content-type":"application/json"})
71
- #headers.update({'appKey':self.open_key})
72
- #headers.update({'appsecret':self.secret_key})
150
+ headers.update({"content-type": "application/json"})
151
+ # headers.update({'appKey':self.open_key})
152
+ # headers.update({'appsecret':self.secret_key})
73
153
 
74
154
  return headers
75
155
 
76
-
77
- def describe(self) -> Dict:
78
- return {}
79
-
80
- def fetch(self, url, method='GET', headers=None, body=None, params=None):
81
- request_headers = headers #self.prepare_request_headers(headers=headers)
156
+ def throttle(self, cost=None):
157
+ now = float(self.milliseconds())
158
+ elapsed = now - self.lastRestRequestTimestamp
159
+ cost = 1 if cost is None else cost
160
+ sleep_time = self.rate_limit * cost
161
+ if elapsed < sleep_time:
162
+ delay = sleep_time - elapsed
163
+ time.sleep(delay / 1000.0)
164
+
165
+ def fetch(self, url, method="GET", headers=None, body=None, params=None):
166
+ request_headers = headers
82
167
  request_body = body
83
168
  request_params = params
84
169
 
@@ -96,10 +181,10 @@ class RestExchange(Exchange):
96
181
  headers=request_headers,
97
182
  data=request_body,
98
183
  params=request_params,
99
- timeout=int(self.timeout / 1000)
184
+ timeout=int(self.timeout / 1000),
100
185
  )
101
186
 
102
- response.encoding = 'utf-8'
187
+ response.encoding = "utf-8"
103
188
 
104
189
  headers = response.headers
105
190
  http_status_code = response.status_code
@@ -108,111 +193,210 @@ class RestExchange(Exchange):
108
193
  json_response = self.parse_json(http_response)
109
194
 
110
195
  except TimeoutError as e:
111
- details = ' '.join([self.id, method, url])
196
+ details = " ".join([self.id, method, url])
112
197
  raise TimeoutError(details) from e
113
-
114
- if json_response:
115
- return json_response
116
198
 
117
- def sign(self, path, market, module, api: Any = 'public', method='GET', headers: Optional[Any] = None, body: Optional[Any] = None, params: Optional[Any] = None, config={}):
199
+ return json_response
200
+
201
+ def is_activate(self, path, security_type) -> bool:
202
+ return self.apis[self.type][security_type][path]["activate"]
203
+
204
+ def sign(
205
+ self,
206
+ path,
207
+ security_type,
208
+ method_type,
209
+ api_type: Any = "public",
210
+ headers: Optional[Any] = None,
211
+ body: Optional[Any] = None,
212
+ params: Optional[Any] = None,
213
+ config={},
214
+ ):
118
215
  pass
119
216
 
120
- def fetch2(self, path, market, module, api: Any = 'public', method='GET', params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}):
121
- # Rate Limit 체크 throttle 처리
122
-
123
- is_activate = self.apis[self.type][market][module][path]['activate']
217
+ def fetch2(
218
+ self, path, security_type, params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}
219
+ ):
220
+ is_activate = self.is_activate(path=path, security_type=security_type)
124
221
  if not is_activate:
125
222
  return {
126
- 'response': {
127
- # 성공 실패 여부
128
- 'success' : '-1',
129
- # 응답코드
130
- 'code': 'fail',
131
- # 응답메세지
132
- 'message': f'지원하지 않는 함수({path}) 입니다.'
133
- }}
223
+ "response": {
224
+ # 성공 실패 여부
225
+ "success": "-1",
226
+ # 응답코드
227
+ "code": "fail",
228
+ # 응답메세지
229
+ "message": f"지원하지 않는 함수({path}) 입니다.",
230
+ }
231
+ }
232
+
233
+ # if self.enableRateLimit:
234
+ # cost = self.calculate_rate_limiter_cost(api, method, path, params, config)
235
+ # self.throttle(cost)
236
+
237
+ # self.lastRestRequestTimestamp = self.milliseconds()
238
+
239
+ method_type = self.apis[self.type][security_type][path]["method"]
240
+ api_type = self.apis[self.type][security_type][path]["api"]
241
+ request = self.sign(path, security_type, method_type, api_type, headers, body, params, config)
242
+ return self.fetch(request["url"], request["method"], request["headers"], request["body"], request["params"])
243
+
244
+ def request(
245
+ self, path, security_type, params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}
246
+ ):
247
+ return self.fetch2(path, security_type, params, headers, body, config)
248
+
249
+ # region base method
250
+ def create_token(self) -> ksxt.models.KsxtTokenResponse:
251
+ raise NotSupportedError(f"{self.id} {self.create_token.__qualname__}() is not supported yet.")
134
252
 
135
- request = self.sign(path, market, module, api, method, headers, body, params, config)
136
- return self.fetch(request['url'], request['method'], request['headers'], request['body'], request['params'])
253
+ @check_token
254
+ def fetch_markets(self, market_name: str) -> ksxt.models.KsxtMarketResponse:
255
+ raise NotSupportedError(f"{self.id} {self.fetch_markets.__qualname__}() is not supported yet.")
137
256
 
138
- def request(self, path, market, module, api: Any='public', method='GET', params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}):
139
- return self.fetch2(path, market, module, api, method, params, headers, body, config)
257
+ @check_token
258
+ def fetch_security(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSecurityResponse:
259
+ raise NotSupportedError(f"{self.id} {self.fetch_security.__qualname__}() is not supported yet.")
140
260
 
261
+ @check_token
262
+ def fetch_ticker(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTickerResponse:
263
+ raise NotSupportedError(f"{self.id} {self.fetch_ticker.__qualname__}() is not supported yet.")
141
264
 
142
- # region public feeder
143
265
  @check_token
144
- def fetch_markets(self, market_name: str):
145
- pass
146
-
266
+ def fetch_orderbook(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSingleOrderBookResponse:
267
+ raise NotSupportedError(f"{self.id} {self.fetch_orderbook.__qualname__}() is not supported yet.")
268
+
147
269
  @check_token
148
- def fetch_security(self, symbol: str, base_market: str = 'KRW'):
149
- pass
150
-
270
+ def fetch_historical_data_index(
271
+ self,
272
+ symbol: str,
273
+ time_frame: str,
274
+ start: Optional[str] = None,
275
+ end: Optional[str] = None,
276
+ base_market: str = "KRW",
277
+ ) -> ksxt.models.KsxtHistoricalDataResponse:
278
+ raise NotSupportedError(f"{self.id} {self.fetch_historical_data_index.__qualname__}() is not supported yet.")
279
+
151
280
  @check_token
152
- def fetch_ticker(self, symbol: str, base_market: str= 'KRW'):
153
- pass
154
-
281
+ def fetch_historical_data(
282
+ self,
283
+ symbol: str,
284
+ time_frame: str,
285
+ start: Optional[str] = None,
286
+ end: Optional[str] = None,
287
+ base_market: str = "KRW",
288
+ ) -> ksxt.models.KsxtHistoricalDataResponse:
289
+ raise NotSupportedError(f"{self.id} {self.fetch_historical_data.__qualname__}() is not supported yet.")
290
+
155
291
  @check_token
156
- def fetch_historical_data(self, symbol: str, time_frame: str, start: Optional[str] = None, end: Optional[str] = None, base_market: str= 'KRW'):
157
- pass
158
-
292
+ def fetch_is_holiday(self, dt: datetime, base_market: str = "KRW") -> ksxt.models.KsxtHolidayResponse:
293
+ raise NotSupportedError(f"{self.id} {self.fetch_is_holiday.__qualname__}() is not supported yet.")
294
+
159
295
  @check_token
160
- def fetch_is_holiday(self, dt: datetime, base_market: str= 'KRW'):
161
- pass
162
- # endregion public feeder
296
+ def fetch_user_info(self, base_market: str = "KRW"):
297
+ raise NotSupportedError(f"{self.id} {self.fetch_user_info.__qualname__}() is not supported yet.")
163
298
 
164
- # region private feeder
165
299
  @check_token
166
- def fetch_user_info(self, base_market: str= 'KRW'):
167
- pass
168
-
300
+ def fetch_balance(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtBalanceResponse:
301
+ raise NotSupportedError(f"{self.id} {self.fetch_balance.__qualname__}() is not supported yet.")
302
+
169
303
  @check_token
170
- def fetch_balance(self, acc_num: str, base_market: str= 'KRW'):
171
- pass
172
-
304
+ def fetch_cash(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtCashResponse:
305
+ raise NotSupportedError(f"{self.id} {self.fetch_cash.__qualname__}() is not supported yet.")
306
+
173
307
  @check_token
174
- def fetch_cash(self, acc_num: str, base_market: str= 'KRW'):
175
- pass
176
-
308
+ def fetch_trade_fee(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTradeFeeResponse:
309
+ raise NotSupportedError(f"{self.id} {self.fetch_trade_fee.__qualname__}() is not supported yet.")
310
+
177
311
  @check_token
178
- def fetch_screener_list(self, base_market: str= 'KRW'):
179
- pass
180
-
312
+ def fetch_screener_list(self, base_market: str = "KRW"):
313
+ raise NotSupportedError(f"{self.id} {self.fetch_screener_list.__qualname__}() is not supported yet.")
314
+
181
315
  @check_token
182
- def fetch_screener(self, screen_id: str, base_market: str= 'KRW'):
183
- pass
184
-
316
+ def fetch_screener(self, screen_id: str, base_market: str = "KRW"):
317
+ raise NotSupportedError(f"{self.id} {self.fetch_screener.__qualname__}() is not supported yet.")
318
+
185
319
  @check_token
186
- def fetch_deposit_history(self, acc_num: str, base_market: str= 'KRW'):
187
- pass
188
-
320
+ def fetch_deposit_history(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtDepositHistoryResponse:
321
+ raise NotSupportedError(f"{self.id} {self.fetch_deposit_history.__qualname__}() is not supported yet.")
322
+
189
323
  @check_token
190
- def fetch_withdrawal_history(self, acc_num: str, base_market: str= 'KRW'):
191
- pass
192
- # endregion private feeder
324
+ def fetch_withdrawal_history(
325
+ self, acc_num: str, base_market: str = "KRW"
326
+ ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
327
+ raise NotSupportedError(f"{self.id} {self.fetch_withdrawal_history.__qualname__}() is not supported yet.")
193
328
 
194
- # region broker
195
329
  @check_token
196
- def create_order(self, acc_num: str, symbol: str, ticket_type: str, price: float, qty: float, otype: str, base_market: str= 'KRW'):
197
- pass
198
-
330
+ def create_order(
331
+ self,
332
+ acc_num: str,
333
+ symbol: str,
334
+ ticket_type: Literal["EntryLong", "EntryShort", "ExitLong", "ExitShort"],
335
+ otype: Literal["limit", "market"],
336
+ price: Optional[float] = 0,
337
+ qty: Optional[float] = 0,
338
+ amount: Optional[float] = 0,
339
+ base_market: str = "KRW",
340
+ ) -> ksxt.models.KsxtCreateOrderResponse:
341
+ raise NotSupportedError(f"{self.id} {self.create_order.__qualname__}() is not supported yet.")
342
+
199
343
  @check_token
200
- def cancel_order(self, acc_num: str, order_id: str, symbol: Optional[str] = '', qty: float = 0, *args, base_market: str= 'KRW'):
201
- pass
202
-
344
+ def cancel_order(
345
+ self, acc_num: str, order_id: str, symbol: Optional[str] = "", qty: float = 0, *args, base_market: str = "KRW"
346
+ ) -> ksxt.models.KsxtCancelOrderResponse:
347
+ raise NotSupportedError(f"{self.id} {self.cancel_order.__qualname__}() is not supported yet.")
348
+
203
349
  @check_token
204
- def modify_order(self, acc_num: str, order_id: str, price: float, qty: float, *args, symbol: Optional[str] = '', base_market: str= 'KRW'):
205
- pass
206
-
350
+ def modify_order(
351
+ self,
352
+ acc_num: str,
353
+ order_id: str,
354
+ price: float,
355
+ qty: float,
356
+ *args,
357
+ symbol: Optional[str] = "",
358
+ base_market: str = "KRW",
359
+ ) -> ksxt.models.KsxtModifyOrderResponse:
360
+ raise NotSupportedError(f"{self.id} {self.modify_order.__qualname__}() is not supported yet.")
361
+
207
362
  @check_token
208
- def fetch_open_order(self, acc_num: str, symbol: Optional[str] = '', start: Optional[str] = None, end: Optional[str] = None, base_market: str= 'KRW'):
209
- pass
210
-
363
+ def fetch_open_order(
364
+ self,
365
+ acc_num: str,
366
+ symbol: Optional[str] = "",
367
+ start: Optional[str] = None,
368
+ end: Optional[str] = None,
369
+ base_market: str = "KRW",
370
+ ) -> ksxt.models.KsxtOpenOrderResponse:
371
+ raise NotSupportedError(f"{self.id} {self.fetch_open_order.__qualname__}() is not supported yet.")
372
+
211
373
  @check_token
212
- def fetch_closed_order(self, acc_num: str, symbol: Optional[str] = '', start: Optional[str] = None, end: Optional[str] = None, base_market: str= 'KRW'):
213
- pass
214
-
374
+ def fetch_closed_order(
375
+ self,
376
+ acc_num: str,
377
+ symbol: Optional[str] = "",
378
+ start: Optional[str] = None,
379
+ end: Optional[str] = None,
380
+ base_market: str = "KRW",
381
+ ) -> ksxt.models.KsxtClosedOrderResponse:
382
+ raise NotSupportedError(f"{self.id} {self.fetch_closed_order.__qualname__}() is not supported yet.")
383
+
215
384
  @check_token
216
- def reserve_order(self, acc_num:str, symbol: str, price: float, qty: float, target_date: str, base_market: str= 'KRW'):
217
- pass
218
- # endregion broker
385
+ def fetch_open_order_detail(
386
+ self, acc_num: str, order_ids: List[str], base_market: str = "KRW"
387
+ ) -> ksxt.models.KsxtOpenOrderResponse:
388
+ raise NotSupportedError(f"{self.id} {self.fetch_open_order_detail.__qualname__}() is not supported yet.")
389
+
390
+ @check_token
391
+ def fetch_closed_order_detail(
392
+ self, acc_num: str, order_ids: List[str], base_market: str = "KRW"
393
+ ) -> ksxt.models.KsxtOpenOrderResponse:
394
+ raise NotSupportedError(f"{self.id} {self.fetch_closed_order_detail.__qualname__}() is not supported yet.")
395
+
396
+ @check_token
397
+ def reserve_order(
398
+ self, acc_num: str, symbol: str, price: float, qty: float, target_date: str, base_market: str = "KRW"
399
+ ):
400
+ raise NotSupportedError(f"{self.id} {self.reserve_order.__qualname__}() is not supported yet.")
401
+
402
+ # endregion base method
ksxt/base/types.py CHANGED
@@ -1,39 +1,4 @@
1
- import types
2
1
  from typing import Union
3
2
 
4
3
 
5
- class Entry:
6
- def __init__(self, path, market, module, api, method, config):
7
- # function key
8
- self.path = path
9
-
10
- # market type : stock, derivative, oversea_stock, oversea_derivative
11
- self.market = market
12
-
13
- # Feeder / Broker
14
- self.module = module
15
-
16
- # Token / Hash / Private / Public
17
- self.api = api
18
-
19
- # GET / POST
20
- self.method = method
21
-
22
- self.config = config
23
-
24
- def unbound_method(_self, params={}):
25
- return _self.request(self.path, self.market, self.module, self.api, self.method, params, config=self.config)
26
-
27
- self.unbound_method = unbound_method
28
-
29
- def __get__(self, instance, owner):
30
- if instance is None:
31
- return self.unbound_method
32
- else:
33
- return types.MethodType(self.unbound_method, instance)
34
-
35
- def __set_name__(self, owner, name):
36
- self.name = name
37
-
38
-
39
- IndexType = Union[str, int]
4
+ IndexType = Union[str, int]