ksxt 0.0.10__py3-none-any.whl → 1.0.1__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/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
- ksxt/async_/base/async_exchange.py +35 -42
- ksxt/async_/koreainvest.py +271 -639
- ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/rate_limiter.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
- ksxt/base/exchange.py +5 -0
- ksxt/base/rate_limiter.py +88 -0
- ksxt/base/rest_exchange.py +52 -26
- ksxt/config/__init__.py +2 -0
- ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/config/bithumb.toml +2 -1
- ksxt/config/upbit.toml +6 -1
- ksxt/koreainvest.py +6 -26
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/METADATA +1 -1
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/RECORD +21 -20
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/WHEEL +1 -1
- ksxt/async_/base/throttler.py +0 -63
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/LICENSE.txt +0 -0
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/top_level.txt +0 -0
ksxt/async_/koreainvest.py
CHANGED
@@ -2,32 +2,34 @@ from datetime import datetime, timedelta
|
|
2
2
|
import json
|
3
3
|
import os
|
4
4
|
import time
|
5
|
-
from typing import Any, Dict, Optional
|
5
|
+
from typing import Any, Dict, Literal, Optional
|
6
|
+
|
7
|
+
import pytz
|
8
|
+
|
6
9
|
from ksxt.api.koreainvest import ImplicitAPI
|
7
10
|
from ksxt.async_.base.async_exchange import AsyncExchange
|
8
11
|
from ksxt.market.manager import MarketManager
|
9
12
|
from ksxt.parser.koreainvest import KoreaInvestParser
|
10
13
|
|
14
|
+
import ksxt.models
|
15
|
+
|
11
16
|
|
12
17
|
class KoreaInvest(AsyncExchange, ImplicitAPI):
|
13
18
|
def __init__(self, config: Dict = None) -> None:
|
14
19
|
super().__init__(config, "koreainvest.toml")
|
15
20
|
self.parser = KoreaInvestParser()
|
16
|
-
|
17
|
-
def safe_symbol(self, base_market: str, security: str) -> str:
|
18
|
-
return f"{security}"
|
21
|
+
self.timezone = pytz.timezone("Asia/Seoul")
|
19
22
|
|
20
23
|
def is_activate(self, path, security_type) -> bool:
|
21
24
|
mode = "dev" if self.is_dev == True else "app"
|
22
25
|
|
23
26
|
tr_id = self.apis[self.type][security_type][path][mode]["tr_id"]
|
24
27
|
|
25
|
-
if not bool(tr_id):
|
28
|
+
if security_type != "token" and not bool(tr_id):
|
26
29
|
return False
|
27
30
|
|
28
31
|
return super().is_activate(path=path, security_type=security_type)
|
29
32
|
|
30
|
-
@AsyncExchange.check_token
|
31
33
|
def sign(
|
32
34
|
self,
|
33
35
|
path,
|
@@ -47,26 +49,24 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
|
|
47
49
|
params["version"] = version
|
48
50
|
destination = self.implode_params(destination, params)
|
49
51
|
|
50
|
-
url = host_url
|
52
|
+
url = f"{host_url}/{destination}"
|
51
53
|
|
52
54
|
tr_id = self.apis[self.type][security_type][path][mode]["tr_id"]
|
53
55
|
authorization_token = f"Bearer {self.token}"
|
54
|
-
|
55
|
-
if "
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
}
|
69
|
-
)
|
56
|
+
|
57
|
+
if api_type == "private":
|
58
|
+
if headers is None:
|
59
|
+
headers = {}
|
60
|
+
headers.update(
|
61
|
+
{
|
62
|
+
"content-type": "application/json",
|
63
|
+
"authorization": authorization_token,
|
64
|
+
"appkey": self.open_key,
|
65
|
+
"appsecret": self.secret_key,
|
66
|
+
"tr_id": tr_id,
|
67
|
+
"custtype": "P",
|
68
|
+
}
|
69
|
+
)
|
70
70
|
|
71
71
|
if method_type.upper() == "POST":
|
72
72
|
body = json.dumps(params)
|
@@ -74,241 +74,57 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
|
|
74
74
|
|
75
75
|
return {"url": url, "method": method_type, "headers": headers, "body": body, "params": params}
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
import logging
|
77
|
+
async def create_token(self) -> ksxt.models.KsxtTokenResponse:
|
78
|
+
params = {"grant_type": "client_credentials", "appkey": self.open_key, "appsecret": self.secret_key}
|
80
79
|
|
81
|
-
|
82
|
-
host_url = self.apis[self.type][mode]["hostname"]
|
83
|
-
destination = self.apis[self.type]["token"]["url"]
|
84
|
-
url = host_url + "/" + destination
|
80
|
+
common_header = self.create_common_header(request_params=params)
|
85
81
|
|
86
|
-
|
82
|
+
response = await self.public_post_generate_token(self.extend(params))
|
87
83
|
|
88
|
-
|
84
|
+
common_response = self.get_common_response(response=response)
|
85
|
+
if common_response.success != "0":
|
86
|
+
return ksxt.models.KsxtTokenResponse(header=common_header, response=common_response, info=None)
|
89
87
|
|
90
|
-
|
88
|
+
parsed_info = self.parser.parse_token(response=response)
|
91
89
|
|
92
|
-
|
93
|
-
res = self.fetch(url=url, method="POST", headers=request_headers, body=body)
|
94
|
-
except Exception as ex:
|
95
|
-
logging.error(ex)
|
96
|
-
return
|
90
|
+
self.save_token(self.open_key, parsed_info.access_token, expired=parsed_info.expired_datetime)
|
97
91
|
|
98
|
-
|
99
|
-
token = res["access_token"]
|
100
|
-
token_expired = res["access_token_token_expired"]
|
101
|
-
self.save_token(self.open_key, token, token_expired)
|
102
|
-
else:
|
103
|
-
logging.error(res["error_description"])
|
92
|
+
return ksxt.models.KsxtTokenResponse(header=common_header, response=common_response, info=parsed_info)
|
104
93
|
|
105
|
-
def
|
106
|
-
if
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
return response
|
113
|
-
|
114
|
-
def get_success_response(self, result):
|
115
|
-
return super().get_success_response(
|
116
|
-
# 성공 실패 여부
|
117
|
-
response_code="0",
|
118
|
-
# 응답 코드
|
119
|
-
msg_code=self.safe_string(result, "msg_cd"),
|
120
|
-
# 응답 메세지
|
121
|
-
msg=self.safe_string(result, "msg1"),
|
122
|
-
# 원본 데이터
|
123
|
-
org_data=result,
|
124
|
-
)
|
125
|
-
|
126
|
-
def get_error_response(self, result):
|
127
|
-
return super().get_error_response(
|
128
|
-
error_code=self.safe_string(result, "msg_cd"),
|
129
|
-
error_message=self.safe_string(result, "msg1"),
|
130
|
-
org_data=result,
|
131
|
-
)
|
132
|
-
|
133
|
-
def update_header(self, response: dict, request_params: dict):
|
134
|
-
response = self.update_success_response_header(
|
135
|
-
response, {"request_time": time.time(), "request_params": request_params}
|
136
|
-
)
|
137
|
-
return response
|
138
|
-
|
139
|
-
# endregion ____
|
140
|
-
|
141
|
-
# region public feeder
|
142
|
-
@AsyncExchange.check_token
|
143
|
-
async def fetch_markets(self, market_name: str):
|
144
|
-
db_path = os.path.join(os.getcwd(), f".ksxt-cache_market.{datetime.now().strftime('%Y%m%d')}.db")
|
145
|
-
manager = MarketManager(db_path=db_path)
|
146
|
-
manager._init()
|
147
|
-
if market_name.lower() == "kospi":
|
148
|
-
result = manager.kospi.all()
|
149
|
-
base_market = "KRW"
|
150
|
-
elif market_name.lower() == "kosdaq":
|
151
|
-
result = manager.kosdaq.all()
|
152
|
-
base_market = "KRW"
|
153
|
-
elif market_name.lower() == "nyse":
|
154
|
-
result = manager.nyse.all()
|
155
|
-
base_market = "USD"
|
156
|
-
elif market_name.lower() == "nasdaq":
|
157
|
-
result = manager.nasdaq.all()
|
158
|
-
base_market = "USD"
|
159
|
-
elif market_name.lower() == "amex":
|
160
|
-
result = manager.amex.all()
|
161
|
-
base_market = "USD"
|
162
|
-
else:
|
163
|
-
return self.get_error_response(
|
164
|
-
error_code="market_error", error_message=f"{market_name} market is not yet supported."
|
94
|
+
def get_common_response(self, response):
|
95
|
+
if "error_code" in response:
|
96
|
+
return self.create_common_response(
|
97
|
+
success="1",
|
98
|
+
msg_code=self.safe_string(response, "error_code"),
|
99
|
+
msg=self.safe_string(response, "error_description"),
|
100
|
+
info=response,
|
165
101
|
)
|
166
102
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
async def fetch_trade_fee(self, symbol: Optional[str] = "", base_market: str = "KRW"):
|
175
|
-
params = {"base_market": base_market}
|
176
|
-
|
177
|
-
result = {"rt_cd": "0", "output": {}}
|
178
|
-
response = self.get_response(result, params)
|
179
|
-
if response["response"]["success"] != "0":
|
180
|
-
return response
|
181
|
-
|
182
|
-
return self.parser.parse_trade_fee(response, base_market)
|
183
|
-
|
184
|
-
async def fetch_ticker(self, symbol: str, base_market: str = "KRW"):
|
185
|
-
if base_market == "KRW":
|
186
|
-
params = {"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": symbol}
|
187
|
-
result = await self.private_get_fetch_ticker_price_krw(self.extend(params))
|
188
|
-
elif base_market == "USD":
|
189
|
-
market_code = await self.get_market_code_in_feeder(symbol=symbol, base_market=base_market)
|
190
|
-
params = {"AUTH": "", "EXCD": market_code, "SYMB": symbol}
|
191
|
-
result = await self.fetchTickerForUS(self.extend(params))
|
192
|
-
else:
|
193
|
-
return self.get_error_response(
|
194
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
103
|
+
if "rt_cd" in response and response["rt_cd"] != "0":
|
104
|
+
return self.create_common_response(
|
105
|
+
success="1",
|
106
|
+
msg_code=self.safe_string(response, "msg_cd"),
|
107
|
+
msg=self.safe_string(response, "msg1"),
|
108
|
+
info=response,
|
195
109
|
)
|
196
110
|
|
197
|
-
response
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
async def fetch_historical_data(
|
204
|
-
self,
|
205
|
-
symbol: str,
|
206
|
-
time_frame: str,
|
207
|
-
start: Optional[str] = None,
|
208
|
-
end: Optional[str] = None,
|
209
|
-
base_market: str = "KRW",
|
210
|
-
):
|
211
|
-
limit = 100
|
212
|
-
|
213
|
-
if end is None:
|
214
|
-
end = KoreaInvest.now(base_market=base_market)
|
215
|
-
|
216
|
-
if start is None:
|
217
|
-
|
218
|
-
if time_frame.endswith("m"):
|
219
|
-
start = end - timedelta(minutes=30)
|
220
|
-
|
221
|
-
if base_market == "KRW":
|
222
|
-
params = {
|
223
|
-
"FID_ETC_CLS_CODE": "",
|
224
|
-
"FID_COND_MRKT_DIV_CODE": "J", # "U"
|
225
|
-
"FID_INPUT_ISCD": symbol,
|
226
|
-
"FID_INPUT_HOUR_1": start.strftime("%H%M%S"), # 업종은 조회 간격만 입력 가능
|
227
|
-
"FID_PW_DATA_INCU_YN": "N",
|
228
|
-
}
|
229
|
-
|
230
|
-
result = await self.private_get_fetch_security_ohlcv_minute_krw(self.extend(params))
|
231
|
-
|
232
|
-
elif time_frame.endswith("D"):
|
233
|
-
start = end - timedelta(days=limit)
|
234
|
-
elif time_frame.endswith("W"):
|
235
|
-
start = end - timedelta(weeks=limit)
|
236
|
-
elif time_frame.endswith("M"):
|
237
|
-
start = end - timedelta(days=limit * 30)
|
238
|
-
elif time_frame.endswith("Y"):
|
239
|
-
start = end - timedelta(days=limit * 365)
|
240
|
-
else:
|
241
|
-
start = end
|
242
|
-
|
243
|
-
if base_market == "KRW":
|
244
|
-
params = {
|
245
|
-
"FID_COND_MRKT_DIV_CODE": "J",
|
246
|
-
"FID_INPUT_ISCD": symbol,
|
247
|
-
"FID_INPUT_DATE_1": start.strftime("%Y%m%d"),
|
248
|
-
"FID_INPUT_DATE_2": end.strftime("%Y%m%d"),
|
249
|
-
"FID_PERIOD_DIV_CODE": time_frame,
|
250
|
-
"FID_ORG_ADJ_PRC": "1",
|
251
|
-
}
|
252
|
-
|
253
|
-
result = await self.private_get_fetch_security_ohlcv_krw(self.extend(params))
|
254
|
-
# index는 구분해서 날려야함
|
255
|
-
# response = self.private_get_fetch_index_ohlcv_krw(self.extend(params))
|
256
|
-
elif base_market == "USD":
|
257
|
-
if time_frame == "D":
|
258
|
-
gubn = "0"
|
259
|
-
elif time_frame == "W":
|
260
|
-
gubn = "1"
|
261
|
-
elif time_frame == "M":
|
262
|
-
gubn = "2"
|
263
|
-
else:
|
264
|
-
return self.get_error_response(
|
265
|
-
error_code="time frame error", error_message=f"{time_frame} time-frame is not supported."
|
266
|
-
)
|
267
|
-
|
268
|
-
market_code = await self.get_market_code_in_feeder(symbol=symbol, base_market=base_market)
|
269
|
-
|
270
|
-
params = {
|
271
|
-
"AUTH": "",
|
272
|
-
"EXCD": market_code,
|
273
|
-
"SYMB": symbol,
|
274
|
-
"GUBN": gubn,
|
275
|
-
"BYMD": end.strftime("%Y%m%d"),
|
276
|
-
"MODP": "1",
|
277
|
-
"KEYB": "",
|
278
|
-
}
|
279
|
-
|
280
|
-
result = await self.fetchOHLCVforUS(self.extend(params))
|
281
|
-
else:
|
282
|
-
return self.get_error_response(
|
283
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
111
|
+
if "response" in response and response["response"]["success"] != "0":
|
112
|
+
return self.create_common_response(
|
113
|
+
success="1",
|
114
|
+
msg_code=self.safe_string(response["response"], "code"),
|
115
|
+
msg=self.safe_string(response["response"], "message"),
|
116
|
+
info=response,
|
284
117
|
)
|
285
118
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
async def fetch_is_holiday(self, dt: datetime, base_market: str = "KRW"):
|
293
|
-
if base_market == "KRW":
|
294
|
-
params = {"BASS_DT": dt.strftime("%Y%m%d"), "CTX_AREA_NK": "", "CTX_AREA_FK": ""}
|
295
|
-
result = await self.private_get_fetch_calendar_holiday_krw(self.extend(params))
|
296
|
-
|
297
|
-
response = self.get_response(result, params)
|
298
|
-
if response["response"]["success"] != "0":
|
299
|
-
return response
|
300
|
-
|
301
|
-
return self.parser.parse_is_holiday(response, base_market)
|
302
|
-
else:
|
303
|
-
return self.get_error_response(
|
304
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
305
|
-
)
|
306
|
-
|
307
|
-
# endregion public feeder
|
119
|
+
return self.create_common_response(
|
120
|
+
success="0",
|
121
|
+
msg_code=self.safe_string(response, "msg_cd"),
|
122
|
+
msg=self.safe_string(response, "msg1"),
|
123
|
+
info=response,
|
124
|
+
)
|
308
125
|
|
309
|
-
|
310
|
-
|
311
|
-
async def fetch_balance(self, acc_num: str, base_market: str = "KRW"):
|
126
|
+
@AsyncExchange.check_token
|
127
|
+
async def fetch_balance(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtBalanceResponse:
|
312
128
|
if base_market == "KRW":
|
313
129
|
params = {
|
314
130
|
"CANO": acc_num[:8],
|
@@ -323,32 +139,23 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
|
|
323
139
|
"CTX_AREA_FK100": "",
|
324
140
|
"CTX_AREA_NK100": "",
|
325
141
|
}
|
142
|
+
else:
|
143
|
+
assert ValueError(f"{base_market} is not valid value")
|
326
144
|
|
327
|
-
|
328
|
-
elif base_market == "USD":
|
329
|
-
market_code = await self.get_market_code_in_feeder(symbol="ALL", base_market=base_market)
|
330
|
-
params = {
|
331
|
-
"CANO": acc_num[:8],
|
332
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
333
|
-
"OVRS_EXCG_CD": market_code,
|
334
|
-
"TR_CRCY_CD": "USD",
|
335
|
-
"CTX_AREA_FK200": "",
|
336
|
-
"CTX_AREA_NK200": "",
|
337
|
-
}
|
145
|
+
common_header = self.create_common_header(request_params=params)
|
338
146
|
|
339
|
-
|
340
|
-
else:
|
341
|
-
return self.get_error_response(
|
342
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
343
|
-
)
|
147
|
+
response = await self.private_get_fetch_balance(self.extend(params))
|
344
148
|
|
345
|
-
|
346
|
-
if
|
347
|
-
return response
|
149
|
+
common_response = self.get_common_response(response=response)
|
150
|
+
if common_response.success != "0":
|
151
|
+
return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
|
348
152
|
|
349
|
-
|
153
|
+
parsed_info = self.parser.parse_balance(response=response, base_market=base_market)
|
350
154
|
|
351
|
-
|
155
|
+
return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
|
156
|
+
|
157
|
+
@AsyncExchange.check_token
|
158
|
+
async def fetch_cash(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtCashResponse:
|
352
159
|
if base_market == "KRW":
|
353
160
|
params = {
|
354
161
|
"CANO": acc_num[:8],
|
@@ -363,297 +170,188 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
|
|
363
170
|
"CTX_AREA_FK100": "",
|
364
171
|
"CTX_AREA_NK100": "",
|
365
172
|
}
|
366
|
-
|
367
|
-
result = await self.private_get_fetch_cash_krw(self.extend(params))
|
368
|
-
elif base_market == "USD":
|
369
|
-
params = {
|
370
|
-
"CANO": acc_num[:8],
|
371
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
372
|
-
# 01: 원화, 02: 외화
|
373
|
-
"WCRC_FRCR_DVSN_CD": "02",
|
374
|
-
"NATN_CD": "840",
|
375
|
-
"TR_MKET_CD": "00",
|
376
|
-
"INQR_DVSN_CD": "00",
|
377
|
-
}
|
378
|
-
|
379
|
-
result = await self.fetchCashForUS(self.extend(params))
|
380
173
|
else:
|
381
|
-
|
382
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
383
|
-
)
|
174
|
+
assert ValueError(f"{base_market} is not valid value")
|
384
175
|
|
385
|
-
|
386
|
-
if response["response"]["success"] != "0":
|
387
|
-
return response
|
176
|
+
common_header = self.create_common_header(request_params=params)
|
388
177
|
|
389
|
-
|
178
|
+
response = await self.private_get_fetch_cash(self.extend(params))
|
390
179
|
|
391
|
-
|
392
|
-
if
|
393
|
-
|
394
|
-
|
395
|
-
result = await self.private_get_fetch_orderbook_krw(self.extend(params))
|
396
|
-
elif base_market == "USD":
|
397
|
-
params = {"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": symbol}
|
180
|
+
common_response = self.get_common_response(response=response)
|
181
|
+
if common_response.success != "0":
|
182
|
+
return ksxt.models.KsxtCashResponse(header=common_header, response=common_response, info=None)
|
398
183
|
|
399
|
-
|
400
|
-
else:
|
401
|
-
return self.get_error_response(
|
402
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
403
|
-
)
|
184
|
+
parsed_info = self.parser.parse_cash(response=response, base_market=base_market)
|
404
185
|
|
405
|
-
|
406
|
-
if response["response"]["success"] != "0":
|
407
|
-
return response
|
186
|
+
return ksxt.models.KsxtCashResponse(header=common_header, response=common_response, info=parsed_info)
|
408
187
|
|
409
|
-
|
410
|
-
|
411
|
-
async def fetch_pnl(self, acc_num: str, include_cost: bool = True, base_market: str = "KRW"):
|
188
|
+
@AsyncExchange.check_token
|
189
|
+
async def fetch_orderbook(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSingleOrderBookResponse:
|
412
190
|
if base_market == "KRW":
|
413
|
-
params = {
|
414
|
-
|
415
|
-
|
416
|
-
"AFHR_FLPR_YN": "N",
|
417
|
-
"OFL_YN": "",
|
418
|
-
"INQR_DVSN": "00",
|
419
|
-
"UNPR_DVSN": "01",
|
420
|
-
"FUND_STTL_ICLD_YN": "N",
|
421
|
-
"FNCG_AMT_AUTO_RDPT_YN": "N",
|
422
|
-
"PRCS_DVSN": "01",
|
423
|
-
"COST_ICLD_YN": "Y" if include_cost else "N",
|
424
|
-
"CTX_AREA_FK100": "",
|
425
|
-
"CTX_AREA_NK100": "",
|
426
|
-
}
|
191
|
+
params = {"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": symbol}
|
192
|
+
else:
|
193
|
+
assert ValueError(f"{base_market} is not valid value")
|
427
194
|
|
428
|
-
|
429
|
-
elif base_market == "USD":
|
430
|
-
params = {
|
431
|
-
"CANO": acc_num[:8],
|
432
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
433
|
-
# 01: 원화, 02: 외화
|
434
|
-
"WCRC_FRCR_DVSN_CD": "02",
|
435
|
-
"NATN_CD": "840",
|
436
|
-
"TR_MKET_CD": "00",
|
437
|
-
"INQR_DVSN_CD": "00",
|
438
|
-
}
|
195
|
+
common_header = self.create_common_header(request_params=params)
|
439
196
|
|
440
|
-
|
441
|
-
else:
|
442
|
-
return self.get_error_response(
|
443
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
444
|
-
)
|
197
|
+
response = await self.private_get_fetch_orderbook(self.extend(params))
|
445
198
|
|
446
|
-
|
447
|
-
if
|
448
|
-
return response
|
199
|
+
common_response = self.get_common_response(response=response)
|
200
|
+
if common_response.success != "0":
|
201
|
+
return ksxt.models.KsxtSingleOrderBookResponse(header=common_header, response=common_response, info=None)
|
449
202
|
|
450
|
-
|
203
|
+
parsed_info = self.parser.parse_orderbook(response=response, base_market=base_market)
|
451
204
|
|
452
|
-
|
453
|
-
params = {"USER_ID": user_id}
|
205
|
+
return ksxt.models.KsxtSingleOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
|
454
206
|
|
207
|
+
@AsyncExchange.check_token
|
208
|
+
async def fetch_security(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSecurityResponse:
|
455
209
|
if base_market == "KRW":
|
456
|
-
|
210
|
+
params = {"PRDT_TYPE_CD": "300", "PDNO": symbol}
|
457
211
|
else:
|
458
|
-
|
459
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
460
|
-
)
|
212
|
+
assert ValueError(f"{base_market} is not valid value")
|
461
213
|
|
462
|
-
|
463
|
-
if response["response"]["success"] != "0":
|
464
|
-
return response
|
214
|
+
common_header = self.create_common_header(request_params=params)
|
465
215
|
|
466
|
-
|
216
|
+
response = await self.private_get_fetch_security_info(self.extend(params))
|
467
217
|
|
468
|
-
|
469
|
-
if
|
470
|
-
|
218
|
+
common_response = self.get_common_response(response=response)
|
219
|
+
if common_response.success != "0":
|
220
|
+
return ksxt.models.KsxtSecurityResponse(header=common_header, response=common_response, info=None)
|
471
221
|
|
472
|
-
|
473
|
-
elif base_market == "USD":
|
474
|
-
market_code = self.get_market_code_in_feeder(symbol="ALL", base_market=base_market)
|
475
|
-
params = {"AUTH": "", "EXCD": market_code, "CO_YN_PRICECUR": 1}
|
476
|
-
result = await self.fetchScreenerForUS(self.extend(params))
|
222
|
+
parsed_info = self.parser.parse_security(response=response, base_market=base_market)
|
477
223
|
|
478
|
-
|
479
|
-
return self.get_error_response(
|
480
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
481
|
-
)
|
482
|
-
|
483
|
-
response = self.get_response(result, params)
|
484
|
-
if response["response"]["success"] != "0":
|
485
|
-
return response
|
224
|
+
return ksxt.models.KsxtSecurityResponse(header=common_header, response=common_response, info=parsed_info)
|
486
225
|
|
487
|
-
|
488
|
-
|
489
|
-
async def fetch_security(self, symbol: str, base_market: str = "KRW"):
|
226
|
+
@AsyncExchange.check_token
|
227
|
+
async def fetch_ticker(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTickerResponse:
|
490
228
|
if base_market == "KRW":
|
491
|
-
params = {"
|
492
|
-
|
493
|
-
result = await self.private_get_fetch_security_info_krw(self.extend(params))
|
494
|
-
elif base_market == "USD":
|
495
|
-
params = {"PRDT_TYPE_CD": "J", "PDNO": symbol}
|
496
|
-
|
497
|
-
result = await self.fetchCashForUS(self.extend(params))
|
229
|
+
params = {"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": symbol}
|
498
230
|
else:
|
499
|
-
|
500
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
501
|
-
)
|
231
|
+
assert ValueError(f"{base_market} is not valid value")
|
502
232
|
|
503
|
-
|
504
|
-
if response["response"]["success"] != "0":
|
505
|
-
return response
|
233
|
+
common_header = self.create_common_header(request_params=params)
|
506
234
|
|
507
|
-
|
235
|
+
response = await self.private_get_fetch_ticker_price(self.extend(params))
|
508
236
|
|
509
|
-
|
237
|
+
common_response = self.get_common_response(response=response)
|
238
|
+
if common_response.success != "0":
|
239
|
+
return ksxt.models.KsxtTickerResponse(header=common_header, response=common_response, info=None)
|
510
240
|
|
511
|
-
|
512
|
-
async def create_order(
|
513
|
-
self,
|
514
|
-
acc_num: str,
|
515
|
-
symbol: str,
|
516
|
-
ticket_type: str,
|
517
|
-
price: float,
|
518
|
-
qty: float,
|
519
|
-
otype: str,
|
520
|
-
base_market: str = "KRW",
|
521
|
-
):
|
522
|
-
if base_market == "KRW":
|
523
|
-
if otype.upper() == "limit".upper():
|
524
|
-
order_dvsn = "00"
|
525
|
-
elif otype.upper() == "market".upper():
|
526
|
-
order_dvsn = "01"
|
241
|
+
parsed_info = self.parser.parse_ticker(response=response, base_market=base_market)
|
527
242
|
|
528
|
-
|
529
|
-
"CANO": acc_num[:8],
|
530
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
531
|
-
"PDNO": symbol,
|
532
|
-
"ORD_DVSN": order_dvsn,
|
533
|
-
"ORD_QTY": str(qty), # string type 으로 설정
|
534
|
-
"ORD_UNPR": str(price), # string type 으로 설정
|
535
|
-
}
|
243
|
+
return ksxt.models.KsxtTickerResponse(header=common_header, response=common_response, info=parsed_info)
|
536
244
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
elif
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
)
|
245
|
+
@AsyncExchange.check_token
|
246
|
+
async def fetch_historical_data_index(
|
247
|
+
self, symbol: str, time_frame: str, start: str | None = None, end: str | None = None, base_market: str = "KRW"
|
248
|
+
) -> ksxt.models.KsxtHistoricalDataResponse:
|
249
|
+
if time_frame.endswith("D"):
|
250
|
+
param_code = "D"
|
251
|
+
elif time_frame.endswith("W") or time_frame.endswith("w"):
|
252
|
+
param_code = "W"
|
253
|
+
elif time_frame.endswith("M"):
|
254
|
+
param_code = "M"
|
255
|
+
elif time_frame.endswith("Y"):
|
256
|
+
param_code = "Y"
|
257
|
+
else:
|
258
|
+
assert ValueError(f"{time_frame} is not valid value")
|
552
259
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
else:
|
558
|
-
return
|
260
|
+
if start is None:
|
261
|
+
start = self.now(base_market) - timedelta(days=50)
|
262
|
+
if end is None:
|
263
|
+
end = self.now(base_market)
|
559
264
|
|
560
|
-
|
265
|
+
if base_market == "KRW":
|
561
266
|
params = {
|
562
|
-
"
|
563
|
-
"
|
564
|
-
"
|
565
|
-
"
|
566
|
-
"
|
567
|
-
"ORD_QTY": str(qty), # string type 으로 설정
|
568
|
-
"SLL_TYPE": sell_type,
|
569
|
-
"OVRS_ORD_UNPR": str(price), # string type 으로 설정
|
570
|
-
"ORD_SVR_DVSN_CD": "0",
|
267
|
+
"FID_COND_MRKT_DIV_CODE": "U",
|
268
|
+
"FID_INPUT_ISCD": symbol,
|
269
|
+
"FID_INPUT_DATE_1": start.strftime("%Y%m%d"),
|
270
|
+
"FID_INPUT_DATE_2": end.strftime("%Y%m%d"),
|
271
|
+
"FID_PERIOD_DIV_CODE": param_code,
|
571
272
|
}
|
572
|
-
|
573
|
-
if ticket_type == "entry_long":
|
574
|
-
result = await self.sendOrderEntryForUS(self.extend(params))
|
575
|
-
elif ticket_type == "exit_long":
|
576
|
-
result = await self.sendOrderExitForUS(self.extend(params))
|
577
|
-
else:
|
578
|
-
return
|
579
273
|
else:
|
580
|
-
|
581
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
582
|
-
)
|
274
|
+
assert ValueError(f"{base_market} is not valid value")
|
583
275
|
|
584
|
-
|
585
|
-
if response["response"]["success"] != "0":
|
586
|
-
return response
|
276
|
+
common_header = self.create_common_header(request_params=params)
|
587
277
|
|
588
|
-
|
278
|
+
response = await self.private_get_fetch_index_ohlcv(self.extend(params))
|
589
279
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
order_id: str,
|
594
|
-
symbol: Optional[str] = "",
|
595
|
-
qty: float = 0,
|
596
|
-
base_market: str = "KRW",
|
597
|
-
**kwargs,
|
598
|
-
):
|
599
|
-
if base_market == "KRW":
|
600
|
-
params = {
|
601
|
-
"CANO": acc_num[:8],
|
602
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
603
|
-
"KRX_FWDG_ORD_ORGNO": "",
|
604
|
-
"ORGN_ODNO": str(order_id),
|
605
|
-
"RVSE_CNCL_DVSN_CD": "02",
|
606
|
-
"ORD_DVSN": "00",
|
607
|
-
"ORD_QTY": str(qty),
|
608
|
-
"ORD_UNPR": str(0),
|
609
|
-
"QTY_ALL_ORD_YN": "N",
|
610
|
-
}
|
611
|
-
|
612
|
-
# 수량 미입력시 전량 취소
|
613
|
-
if qty == 0:
|
614
|
-
params["QTY_ALL_ORD_YN"] = "Y"
|
280
|
+
common_response = self.get_common_response(response=response)
|
281
|
+
if common_response.success != "0":
|
282
|
+
return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
|
615
283
|
|
616
|
-
|
617
|
-
elif base_market == "USD":
|
618
|
-
if qty == 0:
|
619
|
-
return self.get_error_response(
|
620
|
-
error_code="qty_error", error_message=f"{base_market} cancel order need to set qty."
|
621
|
-
)
|
284
|
+
parsed_info = self.parser.parse_historical_index_data(response=response, symbol=symbol, base_market=base_market)
|
622
285
|
|
623
|
-
|
624
|
-
params = {
|
625
|
-
"CANO": acc_num[:8],
|
626
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
627
|
-
"OVRS_EXCG_CD": market_code,
|
628
|
-
"PDNO": symbol,
|
629
|
-
"ORGN_ODNO": str(order_id),
|
630
|
-
"RVSE_CNCL_DVSN_CD": "02",
|
631
|
-
"ORD_QTY": str(qty),
|
632
|
-
"OVRS_ORD_UNPR": str(0),
|
633
|
-
}
|
286
|
+
return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=parsed_info)
|
634
287
|
|
635
|
-
|
288
|
+
@AsyncExchange.check_token
|
289
|
+
async def fetch_historical_data(
|
290
|
+
self, symbol: str, time_frame: str, start: str | None = None, end: str | None = None, base_market: str = "KRW"
|
291
|
+
) -> ksxt.models.KsxtHistoricalDataResponse:
|
292
|
+
if time_frame.endswith("D"):
|
293
|
+
param_code = "D"
|
294
|
+
elif time_frame.endswith("W") or time_frame.endswith("w"):
|
295
|
+
param_code = "W"
|
296
|
+
elif time_frame.endswith("M"):
|
297
|
+
param_code = "M"
|
298
|
+
elif time_frame.endswith("Y"):
|
299
|
+
param_code = "Y"
|
636
300
|
else:
|
637
|
-
|
638
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
639
|
-
)
|
301
|
+
assert ValueError(f"{time_frame} is not valid value")
|
640
302
|
|
641
|
-
|
642
|
-
|
643
|
-
|
303
|
+
if start is None:
|
304
|
+
start = self.now(base_market) - timedelta(days=100)
|
305
|
+
if end is None:
|
306
|
+
end = self.now(base_market)
|
644
307
|
|
645
|
-
|
308
|
+
if base_market == "KRW":
|
309
|
+
params = {
|
310
|
+
"FID_COND_MRKT_DIV_CODE": "J",
|
311
|
+
"FID_INPUT_ISCD": symbol,
|
312
|
+
"FID_INPUT_DATE_1": start.strftime("%Y%m%d"),
|
313
|
+
"FID_INPUT_DATE_2": end.strftime("%Y%m%d"),
|
314
|
+
"FID_PERIOD_DIV_CODE": param_code,
|
315
|
+
"FID_ORG_ADJ_PRC": "0",
|
316
|
+
}
|
317
|
+
else:
|
318
|
+
assert ValueError(f"{base_market} is not valid value")
|
319
|
+
|
320
|
+
if time_frame.endswith("m"):
|
321
|
+
common_header = self.create_common_header(request_params=params)
|
322
|
+
response = await self.private_get_fetch_security_ohlcv_minute(self.extend(params))
|
323
|
+
elif time_frame.endswith("D"):
|
324
|
+
common_header = self.create_common_header(request_params=params)
|
325
|
+
response = await self.private_get_fetch_security_ohlcv_day(self.extend(params))
|
326
|
+
elif time_frame.endswith("W"):
|
327
|
+
common_header = self.create_common_header(request_params=params)
|
328
|
+
response = await self.private_get_fetch_security_ohlcv_week(self.extend(params))
|
329
|
+
elif time_frame.endswith("M"):
|
330
|
+
common_header = self.create_common_header(request_params=params)
|
331
|
+
response = await self.private_get_fetch_security_ohlcv_month(self.extend(params))
|
332
|
+
elif time_frame.endswith("Y"):
|
333
|
+
common_header = self.create_common_header(request_params=params)
|
334
|
+
response = await self.private_get_fetch_security_ohlcv_year(self.extend(params))
|
335
|
+
|
336
|
+
common_response = self.get_common_response(response=response)
|
337
|
+
if common_response.success != "0":
|
338
|
+
return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
|
339
|
+
|
340
|
+
parsed_info = self.parser.parse_historical_data(response=response, symbol=symbol, base_market=base_market)
|
341
|
+
|
342
|
+
return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=parsed_info)
|
646
343
|
|
344
|
+
@AsyncExchange.check_token
|
647
345
|
async def modify_order(
|
648
346
|
self,
|
649
347
|
acc_num: str,
|
650
348
|
order_id: str,
|
651
349
|
price: float,
|
652
350
|
qty: float,
|
653
|
-
|
351
|
+
*args,
|
352
|
+
symbol: str | None = "",
|
654
353
|
base_market: str = "KRW",
|
655
|
-
|
656
|
-
):
|
354
|
+
) -> ksxt.models.KsxtModifyOrderResponse:
|
657
355
|
if base_market == "KRW":
|
658
356
|
params = {
|
659
357
|
"CANO": acc_num[:8],
|
@@ -666,176 +364,110 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
|
|
666
364
|
"ORD_UNPR": str(price),
|
667
365
|
"QTY_ALL_ORD_YN": "N",
|
668
366
|
}
|
669
|
-
|
670
|
-
# 수량 미입력시 전량 수정
|
671
|
-
if qty == 0:
|
672
|
-
params["QTY_ALL_ORD_YN"] = "Y"
|
673
|
-
|
674
|
-
result = await self.private_post_send_modify_order_krw(self.extend(params))
|
675
|
-
elif base_market == "USD":
|
676
|
-
market_code = await self.get_market_code_in_broker(symbol=symbol, base_market=base_market)
|
677
|
-
params = {
|
678
|
-
"CANO": acc_num[:8],
|
679
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
680
|
-
"OVRS_EXCG_CD": market_code,
|
681
|
-
"PDNO": symbol,
|
682
|
-
"ORGN_ODNO": str(order_id),
|
683
|
-
"RVSE_CNCL_DVSN_CD": "01",
|
684
|
-
"ORD_QTY": str(qty),
|
685
|
-
"OVRS_ORD_UNPR": str(price),
|
686
|
-
}
|
687
|
-
|
688
|
-
result = await self.sendModifyOrderForUS(self.extend(params))
|
689
367
|
else:
|
690
|
-
|
691
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
692
|
-
)
|
368
|
+
assert ValueError(f"{base_market} is not valid value")
|
693
369
|
|
694
|
-
|
695
|
-
|
696
|
-
return response
|
370
|
+
common_header = self.create_common_header(request_params=params)
|
371
|
+
response = await self.private_post_send_modify_order(self.extend(params))
|
697
372
|
|
698
|
-
|
373
|
+
common_response = self.get_common_response(response=response)
|
374
|
+
if common_response.success != "0":
|
375
|
+
return ksxt.models.KsxtModifyOrderResponse(header=common_header, response=common_response, info=None)
|
699
376
|
|
700
|
-
|
701
|
-
self,
|
702
|
-
acc_num: str,
|
703
|
-
symbol: Optional[str] = "",
|
704
|
-
start: Optional[str] = None,
|
705
|
-
end: Optional[str] = None,
|
706
|
-
base_market: str = "KRW",
|
707
|
-
):
|
708
|
-
if start is None:
|
709
|
-
start = KoreaInvest.now(base_market=base_market).strftime("%Y%m%d")
|
377
|
+
parsed_info = self.parser.parse_modify_order(response=response, base_market=base_market)
|
710
378
|
|
711
|
-
|
712
|
-
end = KoreaInvest.now(base_market=base_market).strftime("%Y%m%d")
|
379
|
+
return ksxt.models.KsxtModifyOrderResponse(header=common_header, response=common_response, info=parsed_info)
|
713
380
|
|
381
|
+
@AsyncExchange.check_token
|
382
|
+
async def cancel_order(
|
383
|
+
self, acc_num: str, order_id: str, symbol: str | None = "", qty: float = 0, *args, base_market: str = "KRW"
|
384
|
+
) -> ksxt.models.KsxtCancelOrderResponse:
|
714
385
|
if base_market == "KRW":
|
715
386
|
params = {
|
716
387
|
"CANO": acc_num[:8],
|
717
388
|
"ACNT_PRDT_CD": acc_num[-2:],
|
718
|
-
"
|
719
|
-
"
|
720
|
-
"
|
721
|
-
"
|
722
|
-
"
|
723
|
-
"
|
724
|
-
"
|
725
|
-
"ODNO": "",
|
726
|
-
"INQR_DVSN_3": "00",
|
727
|
-
"INQR_DVSN_1": "",
|
728
|
-
"CTX_AREA_FK100": "",
|
729
|
-
"CTX_AREA_NK100": "",
|
389
|
+
"KRX_FWDG_ORD_ORGNO": "",
|
390
|
+
"ORGN_ODNO": str(order_id),
|
391
|
+
"RVSE_CNCL_DVSN_CD": "02",
|
392
|
+
"ORD_DVSN": "00",
|
393
|
+
"ORD_QTY": str(qty),
|
394
|
+
"ORD_UNPR": str(0),
|
395
|
+
"QTY_ALL_ORD_YN": "N",
|
730
396
|
}
|
397
|
+
else:
|
398
|
+
assert ValueError(f"{base_market} is not valid value")
|
731
399
|
|
732
|
-
|
733
|
-
|
734
|
-
market_code = await self.get_market_code_in_broker("ALL", base_market=base_market)
|
735
|
-
params = {
|
736
|
-
"CANO": acc_num[:8],
|
737
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
738
|
-
"PDNO": symbol if symbol is not None else "%",
|
739
|
-
"OVRS_EXCG_CD": market_code,
|
740
|
-
"SORT_SQN": "DS", # DS : 정순, AS : 역순
|
741
|
-
"CTX_AREA_NK200": "",
|
742
|
-
"CTX_AREA_FK200": "",
|
743
|
-
}
|
400
|
+
common_header = self.create_common_header(request_params=params)
|
401
|
+
response = await self.private_post_send_cancel_order(self.extend(params))
|
744
402
|
|
745
|
-
|
746
|
-
|
747
|
-
return
|
748
|
-
error_code="market_error", error_message=f"{base_market} market is not yet supported."
|
749
|
-
)
|
403
|
+
common_response = self.get_common_response(response=response)
|
404
|
+
if common_response.success != "0":
|
405
|
+
return ksxt.models.KsxtCancelOrderResponse(header=common_header, response=common_response, info=None)
|
750
406
|
|
751
|
-
|
752
|
-
if response["response"]["success"] != "0":
|
753
|
-
return response
|
407
|
+
parsed_info = self.parser.parse_cancel_order(response=response, base_market=base_market)
|
754
408
|
|
755
|
-
return
|
409
|
+
return ksxt.models.KsxtCancelOrderResponse(header=common_header, response=common_response, info=parsed_info)
|
756
410
|
|
757
|
-
|
411
|
+
@AsyncExchange.check_token
|
412
|
+
async def create_order(
|
758
413
|
self,
|
759
414
|
acc_num: str,
|
760
|
-
symbol:
|
761
|
-
|
762
|
-
|
415
|
+
symbol: str,
|
416
|
+
ticket_type: Literal["EntryLong"] | Literal["EntryShort"] | Literal["ExitLong"] | Literal["ExitShort"],
|
417
|
+
otype: Literal["limit"] | Literal["market"],
|
418
|
+
price: float | None = 0,
|
419
|
+
qty: float | None = 0,
|
420
|
+
amount: float | None = 0,
|
763
421
|
base_market: str = "KRW",
|
764
|
-
):
|
765
|
-
if
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
"ACNT_PRDT_CD": acc_num[-2:],
|
795
|
-
"PDNO": symbol if symbol is not None else "%",
|
796
|
-
"ORD_STRT_DT": start,
|
797
|
-
"ORD_END_DT": end,
|
798
|
-
"SLL_BUY_DVSN": "00",
|
799
|
-
"CCLD_NCCS_DVSN": "01" if not self.is_dev else "00",
|
800
|
-
"OVRS_EXCG_CD": market_code,
|
801
|
-
"SORT_SQN": "DS", # DS : 정순, AS : 역순
|
802
|
-
"ORD_DT": "",
|
803
|
-
"ORD_GNO_BRNO": "",
|
804
|
-
"ODNO": "",
|
805
|
-
"CTX_AREA_NK200": "",
|
806
|
-
"CTX_AREA_FK200": "",
|
807
|
-
}
|
808
|
-
|
809
|
-
result = await self.fetchClosedOrderForUS(self.extend(params))
|
810
|
-
|
811
|
-
response = self.get_response(result, params)
|
812
|
-
if response["response"]["success"] != "0":
|
813
|
-
return response
|
814
|
-
|
815
|
-
return self.parser.parse_closed_order_history(response, base_market)
|
816
|
-
|
817
|
-
# endregion broker
|
818
|
-
|
819
|
-
async def get_market_code_in_feeder(self, symbol: str, base_market: str = "KRW"):
|
422
|
+
) -> ksxt.models.KsxtCreateOrderResponse:
|
423
|
+
if otype.lower() == "limit":
|
424
|
+
order_dvsn = "00"
|
425
|
+
elif otype.lower() == "market":
|
426
|
+
order_dvsn = "01"
|
427
|
+
params = {
|
428
|
+
"CANO": acc_num[:8],
|
429
|
+
"ACNT_PRDT_CD": acc_num[-2:],
|
430
|
+
"PDNO": symbol,
|
431
|
+
"ORD_DVSN": order_dvsn,
|
432
|
+
"ORD_QTY": str(qty), # string type 으로 설정
|
433
|
+
"ORD_UNPR": str(price), # string type 으로 설정
|
434
|
+
}
|
435
|
+
|
436
|
+
common_header = self.create_common_header(request_params=params)
|
437
|
+
|
438
|
+
if ticket_type == "EntryLong":
|
439
|
+
response = await self.private_post_send_order_entry(self.extend(params))
|
440
|
+
elif ticket_type == "ExitLong":
|
441
|
+
response = await self.private_post_send_order_exit(self.extend(params))
|
442
|
+
|
443
|
+
common_response = self.get_common_response(response=response)
|
444
|
+
if common_response.success != "0":
|
445
|
+
return ksxt.models.KsxtCreateOrderResponse(header=common_header, response=common_response, info=None)
|
446
|
+
|
447
|
+
parsed_info = self.parser.parse_create_order(response=response, base_market=base_market)
|
448
|
+
|
449
|
+
return ksxt.models.KsxtCreateOrderResponse(header=common_header, response=common_response, info=parsed_info)
|
450
|
+
|
451
|
+
def get_market_code_in_feeder(self, symbol: str, base_market: str = "KRW"):
|
820
452
|
if base_market == "KRW":
|
821
453
|
return ""
|
822
454
|
elif base_market == "USD":
|
823
455
|
if symbol.upper() == "ALL":
|
824
456
|
return "NASD"
|
825
457
|
|
826
|
-
response =
|
458
|
+
response = self.fetch_security(symbol=symbol, base_market=base_market)
|
827
459
|
return response["exchange"]
|
828
460
|
else:
|
829
461
|
return ""
|
830
462
|
|
831
|
-
|
463
|
+
def get_market_code_in_broker(self, symbol: str, base_market: str = "KRW"):
|
832
464
|
if base_market == "KRW":
|
833
465
|
return ""
|
834
466
|
elif base_market == "USD":
|
835
467
|
if symbol.upper() == "ALL":
|
836
468
|
return "NASD"
|
837
469
|
|
838
|
-
response =
|
470
|
+
response = self.fetch_security(symbol=symbol, base_market=base_market)
|
839
471
|
exname = response["exchange"]
|
840
472
|
if exname == "NYS":
|
841
473
|
return "NYSE"
|