ksxt 1.0.4__py3-none-any.whl → 1.0.6__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 (75) hide show
  1. ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
  2. ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
  3. ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
  4. ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
  5. ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
  6. ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
  7. ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
  8. ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
  9. ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
  10. ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
  11. ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
  12. ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
  13. ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
  14. ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
  15. ksxt/async_/base/async_exchange.py +23 -17
  16. ksxt/async_/bithumb.py +56 -21
  17. ksxt/async_/koreainvest.py +87 -8
  18. ksxt/async_/upbit.py +67 -24
  19. ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
  20. ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
  21. ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
  22. ksxt/base/__pycache__/rate_limiter.cpython-312.pyc +0 -0
  23. ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
  24. ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
  25. ksxt/base/exchange.py +42 -23
  26. ksxt/base/rest_exchange.py +32 -28
  27. ksxt/bithumb.py +48 -14
  28. ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
  29. ksxt/config/token.toml +3 -7
  30. ksxt/koreainvest.py +37 -8
  31. ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
  32. ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
  33. ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
  34. ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
  35. ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
  36. ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
  37. ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
  38. ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
  39. ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
  40. ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
  41. ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
  42. ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
  43. ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
  44. ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
  45. ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
  46. ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
  47. ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
  48. ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
  49. ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
  50. ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
  51. ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
  52. ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
  53. ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
  54. ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
  55. ksxt/models/balance.py +17 -4
  56. ksxt/models/transaction.py +22 -28
  57. ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
  58. ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
  59. ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
  60. ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
  61. ksxt/parser/bithumb.py +124 -23
  62. ksxt/parser/koreainvest.py +84 -21
  63. ksxt/parser/parser.py +30 -10
  64. ksxt/parser/upbit.py +134 -27
  65. ksxt/upbit.py +55 -18
  66. ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
  67. ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
  68. ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
  69. {ksxt-1.0.4.dist-info → ksxt-1.0.6.dist-info}/METADATA +1 -1
  70. ksxt-1.0.6.dist-info/RECORD +119 -0
  71. {ksxt-1.0.4.dist-info → ksxt-1.0.6.dist-info}/WHEEL +1 -1
  72. ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
  73. ksxt-1.0.4.dist-info/RECORD +0 -120
  74. {ksxt-1.0.4.dist-info → ksxt-1.0.6.dist-info}/LICENSE.txt +0 -0
  75. {ksxt-1.0.4.dist-info → ksxt-1.0.6.dist-info}/top_level.txt +0 -0
Binary file
Binary file
Binary file
Binary file
@@ -85,7 +85,7 @@ class AsyncExchange(RestExchange):
85
85
  self.rate_limiters[api_name].release()
86
86
 
87
87
  async def fetch2(
88
- self, path, security_type, params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}
88
+ self, path, security_type, params={}, headers: Any | None = None, body: Any | None = None, config={}
89
89
  ):
90
90
  is_activate = self.apis[self.type][security_type][path]["activate"]
91
91
  if not is_activate:
@@ -130,8 +130,8 @@ class AsyncExchange(RestExchange):
130
130
  self,
131
131
  symbol: str,
132
132
  time_frame: str,
133
- start: Optional[str] = None,
134
- end: Optional[str] = None,
133
+ start: datetime | None = None,
134
+ end: datetime | None = None,
135
135
  base_market: str = "KRW",
136
136
  ) -> ksxt.models.KsxtHistoricalDataResponse:
137
137
  raise NotSupportedError(f"{self.id} {self.fetch_historical_data.__qualname__}() is not supported yet.")
@@ -143,7 +143,13 @@ class AsyncExchange(RestExchange):
143
143
  raise NotSupportedError(f"{self.id} {self.fetch_user_info.__qualname__}() is not supported yet.")
144
144
 
145
145
  async def fetch_balance(
146
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
146
+ self,
147
+ acc_num: str,
148
+ base_market: str = "KRW",
149
+ excluded_symbols: list[str] | None = None,
150
+ included_symbols: list[str] | None = None,
151
+ filter_delisted: bool = True,
152
+ min_amount: float = 0,
147
153
  ) -> ksxt.models.KsxtBalanceResponse:
148
154
  raise NotSupportedError(f"{self.id} {self.fetch_balance.__qualname__}() is not supported yet.")
149
155
 
@@ -157,12 +163,12 @@ class AsyncExchange(RestExchange):
157
163
  raise NotSupportedError(f"{self.id} {self.fetch_screener.__qualname__}() is not supported yet.")
158
164
 
159
165
  async def fetch_deposit_history(
160
- self, acc_num: str, base_market: str = "KRW"
166
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
161
167
  ) -> ksxt.models.KsxtDepositHistoryResponse:
162
168
  raise NotSupportedError(f"{self.id} {self.fetch_deposit_history.__qualname__}() is not supported yet.")
163
169
 
164
170
  async def fetch_withdrawal_history(
165
- self, acc_num: str, base_market: str = "KRW"
171
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
166
172
  ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
167
173
  raise NotSupportedError(f"{self.id} {self.fetch_withdrawal_history.__qualname__}() is not supported yet.")
168
174
 
@@ -172,15 +178,15 @@ class AsyncExchange(RestExchange):
172
178
  symbol: str,
173
179
  ticket_type: Literal["EntryLong", "EntryShort", "ExitLong", "ExitShort"],
174
180
  otype: Literal["limit", "market"],
175
- price: Optional[float] = 0,
176
- qty: Optional[float] = 0,
177
- amount: Optional[float] = 0,
181
+ price: float | None = 0,
182
+ qty: float | None = 0,
183
+ amount: float | None = 0,
178
184
  base_market: str = "KRW",
179
185
  ) -> ksxt.models.KsxtCreateOrderResponse:
180
186
  raise NotSupportedError(f"{self.id} {self.create_order.__qualname__}() is not supported yet.")
181
187
 
182
188
  async def cancel_order(
183
- self, acc_num: str, order_id: str, symbol: Optional[str] = "", qty: float = 0, *args, base_market: str = "KRW"
189
+ self, acc_num: str, order_id: str, symbol: str | None = "", qty: float = 0, *args, base_market: str = "KRW"
184
190
  ) -> ksxt.models.KsxtCancelOrderResponse:
185
191
  raise NotSupportedError(f"{self.id} {self.cancel_order.__qualname__}() is not supported yet.")
186
192
 
@@ -191,7 +197,7 @@ class AsyncExchange(RestExchange):
191
197
  price: float,
192
198
  qty: float,
193
199
  *args,
194
- symbol: Optional[str] = "",
200
+ symbol: str | None = "",
195
201
  base_market: str = "KRW",
196
202
  ):
197
203
  raise NotSupportedError(f"{self.id} {self.modify_order.__qualname__}() is not supported yet.")
@@ -199,9 +205,9 @@ class AsyncExchange(RestExchange):
199
205
  async def fetch_open_order(
200
206
  self,
201
207
  acc_num: str,
202
- symbol: Optional[str] = "",
203
- start: Optional[str] = None,
204
- end: Optional[str] = None,
208
+ symbol: str | None = "",
209
+ start: datetime | None = None,
210
+ end: datetime | None = None,
205
211
  base_market: str = "KRW",
206
212
  ) -> ksxt.models.KsxtOpenOrderResponse:
207
213
  raise NotSupportedError(f"{self.id} {self.fetch_open_order.__qualname__}() is not supported yet.")
@@ -209,9 +215,9 @@ class AsyncExchange(RestExchange):
209
215
  async def fetch_closed_order(
210
216
  self,
211
217
  acc_num: str,
212
- symbol: Optional[str] = "",
213
- start: Optional[str] = None,
214
- end: Optional[str] = None,
218
+ symbol: str | None = "",
219
+ start: datetime | None = None,
220
+ end: datetime | None = None,
215
221
  base_market: str = "KRW",
216
222
  ) -> ksxt.models.KsxtClosedOrderResponse:
217
223
  raise NotSupportedError(f"{self.id} {self.fetch_closed_order.__qualname__}() is not supported yet.")
ksxt/async_/bithumb.py CHANGED
@@ -3,7 +3,7 @@ import hashlib
3
3
  import hmac
4
4
  import json
5
5
  import time
6
- from datetime import datetime
6
+ from datetime import datetime, timezone
7
7
  from typing import Any, Dict, List, Literal, Optional
8
8
  from urllib.parse import urlencode
9
9
  import uuid
@@ -23,6 +23,10 @@ class Bithumb(AsyncExchange, ImplicitAPI):
23
23
  self.parser = BithumbParser()
24
24
 
25
25
  def safe_symbol(self, base_market: str, security: str) -> str:
26
+ # If security already contains a hyphen, assume it's correctly formatted
27
+ if "-" in security:
28
+ return security
29
+
26
30
  return f"{base_market}-{security}"
27
31
 
28
32
  def sign(
@@ -108,10 +112,19 @@ class Bithumb(AsyncExchange, ImplicitAPI):
108
112
  return ksxt.models.KsxtMarketResponse(header=common_header, response=common_response, info=parsed_info)
109
113
 
110
114
  async def fetch_historical_data(
111
- self, symbol: str, time_frame: str, start: str | None = None, end: str | None = None, base_market: str = "KRW"
115
+ self,
116
+ symbol: str,
117
+ time_frame: str,
118
+ start: datetime | None = None,
119
+ end: datetime | None = None,
120
+ base_market: str = "KRW",
112
121
  ) -> ksxt.models.KsxtHistoricalDataResponse:
113
122
  params = {"market": self.safe_symbol(base_market=base_market, security=symbol), "count": 200}
114
123
 
124
+ if end:
125
+ end_utc = end.astimezone(timezone.utc)
126
+ params.update({"to": end_utc.strftime("%Y-%m-%d %H:%M:%S")})
127
+
115
128
  common_header = self.create_common_header(request_params=params)
116
129
 
117
130
  # TODO : time_frame 을 어떻게 고정시킬까? 우리는 분봉, 일봉, 주봉, 월봉 만 지원한다고 가정하면?
@@ -135,7 +148,10 @@ class Bithumb(AsyncExchange, ImplicitAPI):
135
148
  if common_response.success != "0":
136
149
  return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
137
150
 
138
- parsed_response = self.parser.parse_historical_data(response=response, symbol=symbol, base_market=base_market)
151
+ parsed_response = self.parser.parse_historical_data(
152
+ response=response, symbol=symbol, start=start, end=end, base_market=base_market
153
+ )
154
+
139
155
  return ksxt.models.KsxtHistoricalDataResponse(
140
156
  header=common_header, response=common_response, info=parsed_response
141
157
  )
@@ -220,7 +236,13 @@ class Bithumb(AsyncExchange, ImplicitAPI):
220
236
  return ksxt.models.KsxtMultiOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
221
237
 
222
238
  async def fetch_balance(
223
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
239
+ self,
240
+ acc_num: str,
241
+ base_market: str = "KRW",
242
+ excluded_symbols: list[str] | None = None,
243
+ included_symbols: list[str] | None = None,
244
+ filter_delisted: bool = True,
245
+ min_amount: float = 0,
224
246
  ) -> ksxt.models.KsxtBalanceResponse:
225
247
  params = {}
226
248
 
@@ -235,7 +257,14 @@ class Bithumb(AsyncExchange, ImplicitAPI):
235
257
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
236
258
 
237
259
  # 데이터 파싱
238
- parsed_info = self.parser.parse_balance(response, base_market, excluded_symbols=excluded_symbols)
260
+ parsed_info = self.parser.parse_balance(
261
+ response=response,
262
+ base_market=base_market,
263
+ excluded_symbols=excluded_symbols,
264
+ included_symbols=included_symbols,
265
+ filter_delisted=filter_delisted,
266
+ min_amount=min_amount,
267
+ )
239
268
 
240
269
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
241
270
 
@@ -294,9 +323,9 @@ class Bithumb(AsyncExchange, ImplicitAPI):
294
323
  async def fetch_open_order(
295
324
  self,
296
325
  acc_num: str,
297
- symbol: str | None = "",
298
- start: str | None = None,
299
- end: str | None = None,
326
+ symbol: Optional[str] = "",
327
+ start: datetime | None = None,
328
+ end: datetime | None = None,
300
329
  base_market: str = "KRW",
301
330
  ) -> ksxt.models.KsxtOpenOrderResponse:
302
331
  params = {
@@ -316,7 +345,9 @@ class Bithumb(AsyncExchange, ImplicitAPI):
316
345
  return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=None)
317
346
 
318
347
  # 데이터 파싱
319
- parsed_info = self.parser.parse_open_order_history(response, base_market)
348
+ parsed_info = self.parser.parse_open_order_history(
349
+ response=response, start=start, end=end, base_market=base_market
350
+ )
320
351
 
321
352
  return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=parsed_info)
322
353
 
@@ -324,8 +355,8 @@ class Bithumb(AsyncExchange, ImplicitAPI):
324
355
  self,
325
356
  acc_num: str,
326
357
  symbol: Optional[str] = "",
327
- start: Optional[str] = None,
328
- end: Optional[str] = None,
358
+ start: datetime | None = None,
359
+ end: datetime | None = None,
329
360
  base_market: str = "KRW",
330
361
  ) -> ksxt.models.KsxtClosedOrderResponse:
331
362
  params = {"market": self.safe_symbol(base_market, symbol), "uuids": "", "state": "done"}
@@ -341,7 +372,9 @@ class Bithumb(AsyncExchange, ImplicitAPI):
341
372
  return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=None)
342
373
 
343
374
  # 데이터 파싱
344
- parsed_info = self.parser.parse_closed_order_history(response, base_market)
375
+ parsed_info = self.parser.parse_closed_order_history(
376
+ response=response, start=start, end=end, base_market=base_market
377
+ )
345
378
 
346
379
  return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=parsed_info)
347
380
 
@@ -413,9 +446,9 @@ class Bithumb(AsyncExchange, ImplicitAPI):
413
446
  return ksxt.models.KsxtCreateOrderResponse(header=common_header, response=common_response, info=parsed_info)
414
447
 
415
448
  async def fetch_withdrawal_history(
416
- self, acc_num: str, base_market: str = "KRW"
449
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
417
450
  ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
418
- params = {"state": "done", "uuids": "", "txids": ""}
451
+ params = {"state": "DONE", "uuids": "", "txids": ""}
419
452
 
420
453
  common_header = self.create_common_header(request_params=params)
421
454
 
@@ -428,14 +461,16 @@ class Bithumb(AsyncExchange, ImplicitAPI):
428
461
  return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
429
462
 
430
463
  # 데이터 파싱
431
- parsed_info = self.parser.parse_withdrawal_history(response)
464
+ parsed_info = self.parser.parse_withdrawal_history(
465
+ response=response, start=start, end=end, base_market=base_market
466
+ )
432
467
 
433
468
  return ksxt.models.KsxtWithdrawalHistoryResponse(
434
469
  header=common_header, response=common_response, info=parsed_info
435
470
  )
436
471
 
437
472
  async def fetch_deposit_history(
438
- self, acc_num: str, base_market: str = "KRW"
473
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
439
474
  ) -> ksxt.models.KsxtDepositHistoryResponse:
440
475
  params = {"state": "ACCEPTED", "uuids": "", "txids": ""}
441
476
 
@@ -447,11 +482,11 @@ class Bithumb(AsyncExchange, ImplicitAPI):
447
482
 
448
483
  # 실패 시 오류 응답 반환
449
484
  if common_response.success != "0":
450
- return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
485
+ return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=None)
451
486
 
452
487
  # 데이터 파싱
453
- parsed_info = self.parser.parse_deposit_history(response)
454
-
455
- return ksxt.models.KsxtWithdrawalHistoryResponse(
456
- header=common_header, response=common_response, info=parsed_info
488
+ parsed_info = self.parser.parse_deposit_history(
489
+ response=response, start=start, end=end, base_market=base_market
457
490
  )
491
+
492
+ return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=parsed_info)
@@ -125,7 +125,13 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
125
125
 
126
126
  @AsyncExchange.check_token
127
127
  async def fetch_balance(
128
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
128
+ self,
129
+ acc_num: str,
130
+ base_market: str = "KRW",
131
+ excluded_symbols: list[str] | None = None,
132
+ included_symbols: list[str] | None = None,
133
+ filter_delisted: bool = True,
134
+ min_amount: float = 0,
129
135
  ) -> ksxt.models.KsxtBalanceResponse:
130
136
  if base_market == "KRW":
131
137
  params = {
@@ -153,7 +159,12 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
153
159
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
154
160
 
155
161
  parsed_info = self.parser.parse_balance(
156
- response=response, base_market=base_market, excluded_symbols=excluded_symbols
162
+ response=response,
163
+ base_market=base_market,
164
+ excluded_symbols=excluded_symbols,
165
+ included_symbols=included_symbols,
166
+ filter_delisted=filter_delisted,
167
+ min_amount=min_amount,
157
168
  )
158
169
 
159
170
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
@@ -248,7 +259,12 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
248
259
 
249
260
  @AsyncExchange.check_token
250
261
  async def fetch_historical_data_index(
251
- self, symbol: str, time_frame: str, start: str | None = None, end: str | None = None, base_market: str = "KRW"
262
+ self,
263
+ symbol: str,
264
+ time_frame: str,
265
+ start: datetime | None = None,
266
+ end: datetime | None = None,
267
+ base_market: str = "KRW",
252
268
  ) -> ksxt.models.KsxtHistoricalDataResponse:
253
269
  if time_frame.endswith("D"):
254
270
  param_code = "D"
@@ -285,13 +301,22 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
285
301
  if common_response.success != "0":
286
302
  return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
287
303
 
288
- parsed_info = self.parser.parse_historical_index_data(response=response, symbol=symbol, base_market=base_market)
304
+ parsed_response = self.parser.parse_historical_index_data(
305
+ response=response, symbol=symbol, start=start, end=end, base_market=base_market
306
+ )
289
307
 
290
- return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=parsed_info)
308
+ return ksxt.models.KsxtHistoricalDataResponse(
309
+ header=common_header, response=common_response, info=parsed_response
310
+ )
291
311
 
292
312
  @AsyncExchange.check_token
293
313
  async def fetch_historical_data(
294
- self, symbol: str, time_frame: str, start: str | None = None, end: str | None = None, base_market: str = "KRW"
314
+ self,
315
+ symbol: str,
316
+ time_frame: str,
317
+ start: datetime | None = None,
318
+ end: datetime | None = None,
319
+ base_market: str = "KRW",
295
320
  ) -> ksxt.models.KsxtHistoricalDataResponse:
296
321
  if time_frame.endswith("D"):
297
322
  param_code = "D"
@@ -341,9 +366,63 @@ class KoreaInvest(AsyncExchange, ImplicitAPI):
341
366
  if common_response.success != "0":
342
367
  return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
343
368
 
344
- parsed_info = self.parser.parse_historical_data(response=response, symbol=symbol, base_market=base_market)
369
+ parsed_response = self.parser.parse_historical_data(
370
+ response=response, symbol=symbol, start=start, end=end, base_market=base_market
371
+ )
372
+
373
+ return ksxt.models.KsxtHistoricalDataResponse(
374
+ header=common_header, response=common_response, info=parsed_response
375
+ )
376
+
377
+ @AsyncExchange.check_token
378
+ async def fetch_deposit_history(
379
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
380
+ ) -> ksxt.models.KsxtDepositHistoryResponse:
381
+ params = {"state": "ACCEPTED", "uuids": "", "txids": ""}
382
+
383
+ common_header = self.create_common_header(request_params=params)
345
384
 
346
- return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=parsed_info)
385
+ response = await self.private_get_fetch_deposit_history(self.extend(params))
386
+
387
+ common_response = self.get_common_response(response=response)
388
+
389
+ # 실패 시 오류 응답 반환
390
+ if common_response.success != "0":
391
+ return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
392
+
393
+ # 데이터 파싱
394
+ parsed_info = self.parser.parse_deposit_history(
395
+ response=response, start=start, end=end, base_market=base_market
396
+ )
397
+
398
+ return ksxt.models.KsxtWithdrawalHistoryResponse(
399
+ header=common_header, response=common_response, info=parsed_info
400
+ )
401
+
402
+ @AsyncExchange.check_token
403
+ async def fetch_withdrawal_history(
404
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
405
+ ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
406
+ params = {"state": "done", "uuids": "", "txids": ""}
407
+
408
+ common_header = self.create_common_header(request_params=params)
409
+
410
+ response = await self.private_get_fetch_withdrawal_history(self.extend(params))
411
+
412
+ common_response = self.get_common_response(response=response)
413
+
414
+ # 실패 시 오류 응답 반환
415
+ if common_response.success != "0":
416
+ return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
417
+
418
+ # 데이터 파싱
419
+ parsed_info = self.parser.parse_withdrawal_history(
420
+ response=response, start=start, end=end, base_market=base_market
421
+ )
422
+
423
+ return ksxt.models.KsxtWithdrawalHistoryResponse(
424
+ header=common_header, response=common_response, info=parsed_info
425
+ )
347
426
 
348
427
  @AsyncExchange.check_token
349
428
  async def modify_order(
ksxt/async_/upbit.py CHANGED
@@ -2,7 +2,7 @@ import hashlib
2
2
  import json
3
3
  import time
4
4
  import uuid
5
- from datetime import datetime
5
+ from datetime import datetime, timezone
6
6
  from typing import Any, Dict, List, Literal, Optional
7
7
  from urllib.parse import urlencode
8
8
 
@@ -90,7 +90,7 @@ class Upbit(AsyncExchange, ImplicitAPI):
90
90
  info=response,
91
91
  )
92
92
 
93
- async def fetch_markets(self, base_market: str = "KRW") -> ksxt.models.KsxtMarketResponse:
93
+ async def fetch_markets(self, market_name: str = "KRW") -> ksxt.models.KsxtMarketResponse:
94
94
  params = {"isDetails": "True"}
95
95
 
96
96
  common_header = self.create_common_header(request_params=params)
@@ -101,7 +101,7 @@ class Upbit(AsyncExchange, ImplicitAPI):
101
101
  if common_response.success != "0":
102
102
  return ksxt.models.KsxtMarketResponse(header=common_header, response=common_response, info=None)
103
103
 
104
- parsed_info = self.parser.parse_markets(response=response, base_market=base_market)
104
+ parsed_info = self.parser.parse_markets(response=response, base_market=market_name)
105
105
 
106
106
  return ksxt.models.KsxtMarketResponse(header=common_header, response=common_response, info=parsed_info)
107
107
 
@@ -110,6 +110,10 @@ class Upbit(AsyncExchange, ImplicitAPI):
110
110
  ) -> ksxt.models.KsxtHistoricalDataResponse:
111
111
  params = {"market": self.safe_symbol(base_market, symbol), "count": 200}
112
112
 
113
+ if end:
114
+ end_utc = end.astimezone(timezone.utc)
115
+ params.update({"to": end_utc.strftime("%Y-%m-%d %H:%M:%S")})
116
+
113
117
  # TODO : time_frame 을 어떻게 고정시킬까? 우리는 분봉, 일봉, 주봉, 월봉 만 지원한다고 가정하면?
114
118
  if time_frame.endswith("m"):
115
119
  # TODO : parse number
@@ -135,9 +139,13 @@ class Upbit(AsyncExchange, ImplicitAPI):
135
139
  if common_response.success != "0":
136
140
  return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
137
141
 
138
- parsed_info = self.parser.parse_historical_data(response=response, symbol=symbol, base_market=base_market)
142
+ parsed_response = self.parser.parse_historical_data(
143
+ response=response, symbol=symbol, start=start, end=end, base_market=base_market
144
+ )
139
145
 
140
- return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=parsed_info)
146
+ return ksxt.models.KsxtHistoricalDataResponse(
147
+ header=common_header, response=common_response, info=parsed_response
148
+ )
141
149
 
142
150
  async def fetch_ticker(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTickerResponse:
143
151
  params = {"markets": self.safe_symbol(base_market, symbol)} # 다중 조회 시, 콤마로 구분 ex. 'KRW-BTC, BTC-ETH'
@@ -210,7 +218,13 @@ class Upbit(AsyncExchange, ImplicitAPI):
210
218
  return ksxt.models.KsxtMultiOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
211
219
 
212
220
  async def fetch_balance(
213
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
221
+ self,
222
+ acc_num: str,
223
+ base_market: str = "KRW",
224
+ excluded_symbols: list[str] | None = None,
225
+ included_symbols: list[str] | None = None,
226
+ filter_delisted: bool = True,
227
+ min_amount: float = 0,
214
228
  ) -> ksxt.models.KsxtBalanceResponse:
215
229
  params = {}
216
230
 
@@ -223,7 +237,12 @@ class Upbit(AsyncExchange, ImplicitAPI):
223
237
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
224
238
 
225
239
  parsed_info = self.parser.parse_balance(
226
- response=response, base_market=base_market, excluded_symbols=excluded_symbols
240
+ response=response,
241
+ base_market=base_market,
242
+ excluded_symbols=excluded_symbols,
243
+ included_symbols=included_symbols,
244
+ filter_delisted=filter_delisted,
245
+ min_amount=min_amount,
227
246
  )
228
247
 
229
248
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
@@ -276,7 +295,7 @@ class Upbit(AsyncExchange, ImplicitAPI):
276
295
 
277
296
  async def fetch_closed_order_detail(
278
297
  self, acc_num: str, order_ids: List[str], base_market: str = "KRW"
279
- ) -> ksxt.models.KsxtOpenOrderResponse:
298
+ ) -> ksxt.models.KsxtClosedOrderResponse:
280
299
  params = {
281
300
  "uuids": order_ids,
282
301
  }
@@ -289,12 +308,12 @@ class Upbit(AsyncExchange, ImplicitAPI):
289
308
 
290
309
  # 실패 시 오류 응답 반환
291
310
  if common_response.success != "0":
292
- return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=None)
311
+ return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=None)
293
312
 
294
313
  # 데이터 파싱
295
314
  parsed_info = self.parser.parse_closed_order_history(response, base_market)
296
315
 
297
- return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=parsed_info)
316
+ return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=parsed_info)
298
317
 
299
318
  async def fetch_open_order_detail(
300
319
  self, acc_num: str, order_ids: List[str], base_market: str = "KRW"
@@ -321,16 +340,28 @@ class Upbit(AsyncExchange, ImplicitAPI):
321
340
  async def fetch_closed_order(
322
341
  self,
323
342
  acc_num: str,
324
- symbol: Optional[str] = "",
325
- start: Optional[str] = None,
326
- end: Optional[str] = None,
343
+ symbol: str = "",
344
+ start: datetime | None = None,
345
+ end: datetime | None = None,
327
346
  base_market: str = "KRW",
328
347
  ) -> ksxt.models.KsxtClosedOrderResponse:
329
348
  params = {"state": "done"}
330
349
 
331
- if bool(symbol):
350
+ if symbol:
332
351
  params.update({"market": self.safe_symbol(base_market, symbol)})
333
352
 
353
+ if start and end:
354
+ duration = end - start
355
+ if duration.days > 7:
356
+ raise ValueError("The duration between start and end cannot exceed 7 days.")
357
+
358
+ elif start:
359
+ start_timestamp = int(start.timestamp() * 1000)
360
+ params.update({"start_time": start_timestamp})
361
+ elif end:
362
+ end_timestamp = int(end.timestamp() * 1000)
363
+ params.update({"end_time": end_timestamp})
364
+
334
365
  common_header = self.create_common_header(request_params=params)
335
366
 
336
367
  response = await self.private_get_fetch_closed_order(self.extend(params))
@@ -339,21 +370,24 @@ class Upbit(AsyncExchange, ImplicitAPI):
339
370
  if common_response.success != "0":
340
371
  return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=None)
341
372
 
342
- parsed_info = self.parser.parse_closed_order_history(response=response, base_market=base_market)
373
+ # 데이터 파싱
374
+ parsed_info = self.parser.parse_closed_order_history(
375
+ response=response, start=start, end=end, base_market=base_market
376
+ )
343
377
 
344
378
  return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=parsed_info)
345
379
 
346
380
  async def fetch_open_order(
347
381
  self,
348
382
  acc_num: str,
349
- symbol: str | None = "",
350
- start: str | None = None,
351
- end: str | None = None,
383
+ symbol: str = "",
384
+ start: datetime | None = None,
385
+ end: datetime | None = None,
352
386
  base_market: str = "KRW",
353
387
  ) -> ksxt.models.KsxtOpenOrderResponse:
354
388
  params = {"state": "wait"}
355
389
 
356
- if bool(symbol):
390
+ if symbol:
357
391
  params.update({"market": self.safe_symbol(base_market, symbol)})
358
392
 
359
393
  common_header = self.create_common_header(request_params=params)
@@ -364,12 +398,15 @@ class Upbit(AsyncExchange, ImplicitAPI):
364
398
  if common_response.success != "0":
365
399
  return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=None)
366
400
 
367
- parsed_info = self.parser.parse_open_order_history(response=response, base_market=base_market)
401
+ # 데이터 파싱
402
+ parsed_info = self.parser.parse_open_order_history(
403
+ response=response, start=start, end=end, base_market=base_market
404
+ )
368
405
 
369
406
  return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=parsed_info)
370
407
 
371
408
  async def fetch_withdrawal_history(
372
- self, acc_num: str, base_market: str = "KRW"
409
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
373
410
  ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
374
411
  params = {"currency": base_market, "state": "DONE"}
375
412
 
@@ -381,14 +418,17 @@ class Upbit(AsyncExchange, ImplicitAPI):
381
418
  if common_response.success != "0":
382
419
  return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
383
420
 
384
- parsed_info = self.parser.parse_withdrawal_history(response=response, base_market=base_market)
421
+ # 데이터 파싱
422
+ parsed_info = self.parser.parse_withdrawal_history(
423
+ response=response, start=start, end=end, base_market=base_market
424
+ )
385
425
 
386
426
  return ksxt.models.KsxtWithdrawalHistoryResponse(
387
427
  header=common_header, response=common_response, info=parsed_info
388
428
  )
389
429
 
390
430
  async def fetch_deposit_history(
391
- self, acc_num: str, base_market: str = "KRW"
431
+ self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
392
432
  ) -> ksxt.models.KsxtDepositHistoryResponse:
393
433
  params = {"currency": base_market, "state": "ACCEPTED"}
394
434
 
@@ -400,7 +440,10 @@ class Upbit(AsyncExchange, ImplicitAPI):
400
440
  if common_response.success != "0":
401
441
  return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=None)
402
442
 
403
- parsed_info = self.parser.parse_deposit_history(response=response, base_market=base_market)
443
+ # 데이터 파싱
444
+ parsed_info = self.parser.parse_deposit_history(
445
+ response=response, start=start, end=end, base_market=base_market
446
+ )
404
447
 
405
448
  return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=parsed_info)
406
449