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.
- 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 +10 -12
- 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.8.dist-info → ksxt-0.0.9.dist-info}/METADATA +11 -1
- ksxt-0.0.9.dist-info/RECORD +119 -0
- {ksxt-0.0.8.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.8.dist-info/RECORD +0 -49
- {ksxt-0.0.8.dist-info → ksxt-0.0.9.dist-info}/LICENSE.txt +0 -0
- {ksxt-0.0.8.dist-info → ksxt-0.0.9.dist-info}/top_level.txt +0 -0
ksxt/base/rest_exchange.py
CHANGED
@@ -1,28 +1,41 @@
|
|
1
1
|
import json
|
2
|
+
import logging
|
3
|
+
import toml
|
2
4
|
import os
|
3
|
-
from
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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 =
|
32
|
+
type = "rest"
|
24
33
|
|
25
|
-
|
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
|
-
|
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
|
-
|
44
|
-
|
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
|
51
|
-
|
92
|
+
def is_valid_token(self) -> bool:
|
93
|
+
self.load_token()
|
94
|
+
if self.token_expired is None:
|
95
|
+
return False
|
52
96
|
|
53
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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 =
|
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 =
|
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
|
-
|
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(
|
121
|
-
|
122
|
-
|
123
|
-
is_activate = self.
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
-
|
136
|
-
|
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
|
-
|
139
|
-
|
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
|
145
|
-
|
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
|
149
|
-
|
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
|
153
|
-
|
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
|
157
|
-
|
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
|
161
|
-
|
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
|
167
|
-
|
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
|
171
|
-
|
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
|
175
|
-
|
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=
|
179
|
-
|
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=
|
183
|
-
|
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=
|
187
|
-
|
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(
|
191
|
-
|
192
|
-
|
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(
|
197
|
-
|
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(
|
201
|
-
|
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(
|
205
|
-
|
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(
|
209
|
-
|
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(
|
213
|
-
|
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
|
217
|
-
|
218
|
-
|
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
|
-
|
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]
|