ksxt 1.0.5__py3-none-any.whl → 1.0.7__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 (78) 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 +7 -1
  16. ksxt/async_/bithumb.py +19 -2
  17. ksxt/async_/koreainvest.py +13 -2
  18. ksxt/async_/upbit.py +15 -4
  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 +12 -1
  26. ksxt/base/rest_exchange.py +7 -1
  27. ksxt/bithumb.py +19 -2
  28. ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
  29. ksxt/config/token.toml +2 -6
  30. ksxt/koreainvest.py +13 -2
  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 -30
  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 +41 -17
  62. ksxt/parser/koreainvest.py +28 -13
  63. ksxt/parser/parser.py +9 -5
  64. ksxt/parser/upbit.py +50 -19
  65. ksxt/upbit.py +13 -2
  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.5.dist-info → ksxt-1.0.7.dist-info}/LICENSE.txt +1 -1
  70. {ksxt-1.0.5.dist-info → ksxt-1.0.7.dist-info}/METADATA +2 -2
  71. ksxt-1.0.7.dist-info/RECORD +119 -0
  72. ksxt/api/auto/__pycache__/bithumb.cpython-312.pyc +0 -0
  73. ksxt/api/auto/__pycache__/koreainvest.cpython-312.pyc +0 -0
  74. ksxt/api/auto/__pycache__/upbit.cpython-312.pyc +0 -0
  75. ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
  76. ksxt-1.0.5.dist-info/RECORD +0 -123
  77. {ksxt-1.0.5.dist-info → ksxt-1.0.7.dist-info}/WHEEL +0 -0
  78. {ksxt-1.0.5.dist-info → ksxt-1.0.7.dist-info}/top_level.txt +0 -0
Binary file
Binary file
Binary file
Binary file
@@ -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: list[str] | None = 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
 
ksxt/async_/bithumb.py CHANGED
@@ -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(
@@ -232,7 +236,13 @@ class Bithumb(AsyncExchange, ImplicitAPI):
232
236
  return ksxt.models.KsxtMultiOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
233
237
 
234
238
  async def fetch_balance(
235
- 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,
236
246
  ) -> ksxt.models.KsxtBalanceResponse:
237
247
  params = {}
238
248
 
@@ -247,7 +257,14 @@ class Bithumb(AsyncExchange, ImplicitAPI):
247
257
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
248
258
 
249
259
  # 데이터 파싱
250
- 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
+ )
251
268
 
252
269
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
253
270
 
@@ -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)
ksxt/async_/upbit.py CHANGED
@@ -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
 
@@ -218,7 +218,13 @@ class Upbit(AsyncExchange, ImplicitAPI):
218
218
  return ksxt.models.KsxtMultiOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
219
219
 
220
220
  async def fetch_balance(
221
- 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,
222
228
  ) -> ksxt.models.KsxtBalanceResponse:
223
229
  params = {}
224
230
 
@@ -231,7 +237,12 @@ class Upbit(AsyncExchange, ImplicitAPI):
231
237
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
232
238
 
233
239
  parsed_info = self.parser.parse_balance(
234
- 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,
235
246
  )
236
247
 
237
248
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
Binary file
ksxt/base/exchange.py CHANGED
@@ -139,7 +139,15 @@ class Exchange:
139
139
  """
140
140
  pass
141
141
 
142
- def fetch_balance(self, acc_num: str, base_market: str = "KRW", excluded_symbols: list[str] | None = None):
142
+ def fetch_balance(
143
+ self,
144
+ acc_num: str,
145
+ base_market: str = "KRW",
146
+ excluded_symbols: list[str] | None = None,
147
+ included_symbols: list[str] | None = None,
148
+ filter_delisted: bool = True,
149
+ min_amount: float = 0,
150
+ ):
143
151
  """
144
152
  보유 자산 조회
145
153
 
@@ -147,6 +155,9 @@ class Exchange:
147
155
  acc_num (str): 계좌 번호
148
156
  base_market (str, optional): Market 구분 코드. Defaults to 'KRW'.
149
157
  excluded_symbols (list[str] | None, optional): 제외할 종목 리스트. Defaults to None.
158
+ included_symbols (list[str] | None, optional): 포함할 종목 리스트. Defaults to None.
159
+ filter_delisted (bool, optional): 거래 지원 종료되거나 상장 폐지된 종목 필터링 여부. Defaults to True.
160
+ min_amount (float, optional): 최소 자산 금액 필터링. Defaults to 0.
150
161
  """
151
162
  pass
152
163
 
@@ -319,7 +319,13 @@ class RestExchange(Exchange):
319
319
 
320
320
  @check_token
321
321
  def fetch_balance(
322
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: list[str] | None = None
322
+ self,
323
+ acc_num: str,
324
+ base_market: str = "KRW",
325
+ excluded_symbols: list[str] | None = None,
326
+ included_symbols: list[str] | None = None,
327
+ filter_delisted: bool = True,
328
+ min_amount: float = 0,
323
329
  ) -> ksxt.models.KsxtBalanceResponse:
324
330
  raise NotSupportedError(f"{self.id} {self.fetch_balance.__qualname__}() is not supported yet.")
325
331
 
ksxt/bithumb.py CHANGED
@@ -25,6 +25,10 @@ class Bithumb(RestExchange, ImplicitAPI):
25
25
  self.timezone = pytz.timezone("Asia/Seoul")
26
26
 
27
27
  def safe_symbol(self, base_market: str, security: str) -> str:
28
+ # If security already contains a hyphen, assume it's correctly formatted
29
+ if "-" in security:
30
+ return security
31
+
28
32
  return f"{base_market}-{security}"
29
33
 
30
34
  def safe_security(self, symbol: str) -> str:
@@ -229,7 +233,13 @@ class Bithumb(RestExchange, ImplicitAPI):
229
233
  return ksxt.models.KsxtMultiOrderBookResponse(header=common_header, response=common_response, info=parsed_info)
230
234
 
231
235
  def fetch_balance(
232
- self, acc_num: str, base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
236
+ self,
237
+ acc_num: str,
238
+ base_market: str = "KRW",
239
+ excluded_symbols: list[str] | None = None,
240
+ included_symbols: list[str] | None = None,
241
+ filter_delisted: bool = True,
242
+ min_amount: float = 0,
233
243
  ) -> ksxt.models.KsxtBalanceResponse:
234
244
  params = {}
235
245
 
@@ -244,7 +254,14 @@ class Bithumb(RestExchange, ImplicitAPI):
244
254
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=None)
245
255
 
246
256
  # 데이터 파싱
247
- parsed_info = self.parser.parse_balance(response, base_market, excluded_symbols=excluded_symbols)
257
+ parsed_info = self.parser.parse_balance(
258
+ response=response,
259
+ base_market=base_market,
260
+ excluded_symbols=excluded_symbols,
261
+ included_symbols=included_symbols,
262
+ filter_delisted=filter_delisted,
263
+ min_amount=min_amount,
264
+ )
248
265
 
249
266
  return ksxt.models.KsxtBalanceResponse(header=common_header, response=common_response, info=parsed_info)
250
267
 
ksxt/config/token.toml CHANGED
@@ -1,7 +1,3 @@
1
1
  [PSXkvBM1hQXJDRHg2rLvC7Tr8SoyPudlbx9o]
2
- token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0b2tlbiIsImF1ZCI6ImQ0N2EzYjY4LTlkMjQtNGE3YS04YmU2LTNjOWI5MzVmZDZhZCIsInByZHRfY2QiOiIiLCJpc3MiOiJ1bm9ndyIsImV4cCI6MTcyMzAzOTYzOSwiaWF0IjoxNzIyOTUzMjM5LCJqdGkiOiJQU1hrdkJNMWhRWEpEUkhnMnJMdkM3VHI4U295UHVkbGJ4OW8ifQ.573I5Sdj6339IWT5gxhdTFFeWCJDu_ukVAu5QbH9X_SU_laTjhFPttlKBn3HJZzmhYBV89BBcwnYiCwGFU9PFg"
3
- expired = 2024-08-07T23:07:19
4
-
5
- [PSo9UuHWHtg1QzRkyu1WeXYERyUkpRK9LSii]
6
- token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0b2tlbiIsImF1ZCI6ImNhY2NjNGZhLWMxMzktNGE5MC1hNjg2LTI2OTVmZmNiZmQ0NyIsInByZHRfY2QiOiIiLCJpc3MiOiJ1bm9ndyIsImV4cCI6MTcyMzM3ODExNSwiaWF0IjoxNzIzMjkxNzE1LCJqdGkiOiJQU285VXVIV0h0ZzFRelJreXUxV2VYWUVSeVVrcFJLOUxTaWkifQ.EnsBporS5hoD7Prx_fvXoklkxvx1u0Swp3jL9MXv3GnXtU_totbAtfDqsHWexQGJNqgEAPe6Bd2L2M0rCNUpCg"
7
- expired = 2024-08-11T21:08:35
2
+ token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0b2tlbiIsImF1ZCI6IjEyYzYxZWIxLTU3YzQtNGFiZC1iN2JhLTM0OGIwOTBjY2NlMyIsInByZHRfY2QiOiIiLCJpc3MiOiJ1bm9ndyIsImV4cCI6MTcxOTM1OTE1NiwiaWF0IjoxNzE5MjcyNzU2LCJqdGkiOiJQU1hrdkJNMWhRWEpEUkhnMnJMdkM3VHI4U295UHVkbGJ4OW8ifQ.B1CJ7IMEkkqVpQ7ECM8otr6lVVmV2Yp_bRaBBRlcOo29MIQZ5z8g5oEcXyO-ghaUa8UJZguuo8Q7iQreRBYkZg"
3
+ expired = "2024-06-26 08:45:56"
ksxt/koreainvest.py CHANGED
@@ -125,7 +125,13 @@ class KoreaInvest(RestExchange, ImplicitAPI):
125
125
 
126
126
  @RestExchange.check_token
127
127
  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(RestExchange, 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)
Binary file
ksxt/models/balance.py CHANGED
@@ -1,4 +1,4 @@
1
- from pydantic import BaseModel
1
+ from pydantic import BaseModel, model_validator
2
2
  from typing import List
3
3
 
4
4
  from ksxt.models.common import GeneralResponse
@@ -7,14 +7,27 @@ from ksxt.models.common import GeneralResponse
7
7
  class BalanceData(BaseModel):
8
8
  symbol: str
9
9
  name: str
10
- evaluation_price: float
10
+
11
11
  price: float
12
- pnl_amount: float
13
- pnl_ratio: float
12
+ evaluation_price: float
13
+
14
14
  qty: float
15
15
  free_qty: float
16
16
  used_qty: float
17
17
 
18
+ amount: float | None = 0.0
19
+ evaluation_amount: float | None = 0.0
20
+ pnl: float | None = 0.0
21
+ pnl_ratio: float | None = 0.0
22
+
23
+ @model_validator(mode="after")
24
+ def calculate_fields(cls, values):
25
+ values.amount = values.price * values.qty
26
+ values.evaluation_amount = values.evaluation_price * values.qty
27
+ values.pnl = values.evaluation_price - values.price
28
+ values.pnl_ratio = values.pnl / values.price if values.price != 0 else 0.0
29
+ return values
30
+
18
31
 
19
32
  class BalanceInfo(BaseModel):
20
33
  currency: str
@@ -1,5 +1,5 @@
1
1
  from datetime import datetime
2
- from typing import List, Optional
2
+ from typing import List
3
3
  from pydantic import BaseModel
4
4
 
5
5
  from ksxt.models.common import GeneralResponse
@@ -8,45 +8,37 @@ from ksxt.models.common import GeneralResponse
8
8
  class TransactionInfo(BaseModel):
9
9
  # 주문 고유 아이디
10
10
  uuid: str
11
- # 주문 종류 (ask, bid, deposit, withdrawal)
12
- type: str
13
-
14
- # 금액
15
- amount: float
16
- # 세금
17
- tax: Optional[float] = 0
18
- # 수수료
19
- fee: Optional[float] = 0
20
-
21
11
  # 계좌 번호
22
- account_id: Optional[str] = None
23
- # 화폐 통화 정보
24
- currency: Optional[str] = None
12
+ account_id: str | None = None
25
13
 
26
- # 주문 생성 시간
27
- created_at: datetime
14
+ # 주문 종류 (ask, bid, deposit, withdrawal)
15
+ transaction_type: str
28
16
 
17
+ # order type (limit, market, default)
18
+ order_type: str | None = None
19
+
20
+ # position (long, short)
21
+ tr_position: str | None = None
29
22
 
30
- class OpenedOrderInfo(TransactionInfo):
31
23
  # 종목 정보
32
24
  symbol: str
33
25
  # 가격
34
26
  price: float
35
27
  # 수량
36
28
  qty: float
37
- # 주문 방식
38
- order_type: Optional[str]
29
+ # 금액
30
+ amount: float
39
31
 
32
+ # 세금
33
+ tax: float | None = 0
34
+ # 수수료
35
+ fee: float | None = 0
40
36
 
41
- class ClosedOrderInfo(TransactionInfo):
42
- # 종목 정보
43
- symbol: str
44
- # 가격
45
- price: float
46
- # 수량
47
- qty: float
48
- # 주문 방식
49
- order_type: Optional[str]
37
+ # 화폐 통화 정보
38
+ currency: str | None = None
39
+
40
+ # 주문 생성 시간
41
+ created_at: datetime
50
42
 
51
43
 
52
44
  class WithdrawalHistory(BaseModel):
@@ -58,11 +50,11 @@ class DepositHistory(BaseModel):
58
50
 
59
51
 
60
52
  class OpenedOrderHistory(BaseModel):
61
- history: List[OpenedOrderInfo]
53
+ history: List[TransactionInfo]
62
54
 
63
55
 
64
56
  class ClosedOrderHistory(BaseModel):
65
- history: List[ClosedOrderInfo]
57
+ history: List[TransactionInfo]
66
58
 
67
59
 
68
60
  class KsxtWithdrawalHistoryResponse(GeneralResponse[WithdrawalHistory]):
ksxt/parser/bithumb.py CHANGED
@@ -1,13 +1,10 @@
1
1
  from datetime import datetime, timezone
2
- from operator import attrgetter
3
2
  from typing import Dict, List, Optional
4
3
 
5
4
  from ksxt.models.transaction import (
6
5
  ClosedOrderHistory,
7
- ClosedOrderInfo,
8
6
  DepositHistory,
9
7
  OpenedOrderHistory,
10
- OpenedOrderInfo,
11
8
  TransactionInfo,
12
9
  WithdrawalHistory,
13
10
  )
@@ -24,6 +21,10 @@ from ksxt.utils import safer, sorter
24
21
 
25
22
  class BithumbParser(BaseParser):
26
23
  def safe_symbol(self, base_market: str, security: str) -> str:
24
+ # If security already contains a hyphen, assume it's correctly formatted
25
+ if "-" in security:
26
+ return security
27
+
27
28
  return f"{base_market}-{security}"
28
29
 
29
30
  def parse_markets(self, response: List[Dict], base_market: str = "KRW") -> MarketInfo:
@@ -175,7 +176,13 @@ class BithumbParser(BaseParser):
175
176
  return ask_data, bid_data
176
177
 
177
178
  def parse_balance(
178
- self, response: List[Dict], base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
179
+ self,
180
+ response: List[Dict],
181
+ base_market: str = "KRW",
182
+ excluded_symbols: Optional[list[str]] = None,
183
+ included_symbols: Optional[list[str]] = None,
184
+ filter_delisted: bool = True,
185
+ min_amount: float = 0,
179
186
  ) -> BalanceInfo:
180
187
  # 1. Filter out entries where 'currency' is not the base_market
181
188
  # 2. Ensure 'unit_currency' is the base_market
@@ -186,11 +193,18 @@ class BithumbParser(BaseParser):
186
193
  if data["currency"] != base_market
187
194
  and data["unit_currency"] == base_market
188
195
  and (excluded_symbols is None or data["currency"] not in excluded_symbols)
196
+ and (included_symbols is None or self.safe_symbol(base_market, data["currency"]) in included_symbols)
189
197
  ]
190
198
 
191
199
  # Initialize balance list
192
200
  balances = [self._parse_balance(data, base_market) for data in filtered_data]
193
201
 
202
+ if filter_delisted:
203
+ balances = [balance for balance in balances if balance.price > 0]
204
+
205
+ if min_amount > 0:
206
+ balances = [balance for balance in balances if balance.amount > min_amount]
207
+
194
208
  # 총 매입금액
195
209
  total_amount = sum(bal.price * bal.qty for bal in balances)
196
210
  total_evaluation_amount = sum(bal.evaluation_price * bal.qty for bal in balances)
@@ -212,8 +226,6 @@ class BithumbParser(BaseParser):
212
226
  name=self.safe_symbol(base_market, safer.safe_string(data, "currency")),
213
227
  evaluation_price=0, # 필요에 따라 적절히 설정
214
228
  price=safer.safe_number(data, "avg_buy_price"),
215
- pnl_amount=0, # 필요에 따라 적절히 설정
216
- pnl_ratio=0, # 필요에 따라 적절히 설정
217
229
  qty=safer.safe_number(data, "balance"),
218
230
  free_qty=safer.safe_number(data, "balance") - safer.safe_number(data, "locked"),
219
231
  used_qty=safer.safe_number(data, "locked"),
@@ -287,18 +299,21 @@ class BithumbParser(BaseParser):
287
299
 
288
300
  return OpenedOrderHistory(history=orders)
289
301
 
290
- def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
291
- return OpenedOrderInfo(
302
+ def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> TransactionInfo:
303
+ return TransactionInfo(
292
304
  uuid=safer.safe_string(order, "uuid"),
293
- type=safer.safe_string(order, "side"),
305
+ account_id="",
306
+ transaction_type=safer.safe_string(order, "side"),
307
+ order_type=safer.safe_string(order, "ord_type"),
308
+ tr_position="long",
294
309
  symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
295
310
  price=safer.safe_number(order, "price"),
296
311
  qty=safer.safe_number(order, "volume"),
297
312
  amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
298
313
  tax=0,
299
314
  fee=safer.safe_number(order, "reserved_fee"),
315
+ currency=base_market,
300
316
  created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
301
- order_type=safer.safe_string(order, "ord_type"),
302
317
  )
303
318
 
304
319
  def parse_closed_order_history(
@@ -318,18 +333,21 @@ class BithumbParser(BaseParser):
318
333
 
319
334
  return ClosedOrderHistory(history=orders)
320
335
 
321
- def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
322
- return ClosedOrderInfo(
336
+ def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> TransactionInfo:
337
+ return TransactionInfo(
323
338
  uuid=safer.safe_string(order, "uuid"),
324
- type=safer.safe_string(order, "side"),
325
- symbol=safer.safe_string(order, "market"),
339
+ account_id="",
340
+ transaction_type=safer.safe_string(order, "side"),
341
+ order_type=safer.safe_string(order, "ord_type"),
342
+ tr_position="long",
343
+ symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
326
344
  price=safer.safe_number(order, "price"),
327
345
  qty=safer.safe_number(order, "volume"),
328
346
  amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
329
347
  tax=0,
330
348
  fee=safer.safe_number(order, "reserved_fee"),
349
+ currency=base_market,
331
350
  created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
332
- order_type=safer.safe_string(order, "ord_type"),
333
351
  )
334
352
 
335
353
  def parse_cancel_order(self, response: dict, base_market: str = "KRW") -> CancelOrderResponse:
@@ -383,10 +401,16 @@ class BithumbParser(BaseParser):
383
401
  def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
384
402
  return TransactionInfo(
385
403
  uuid=safer.safe_string(item, "uuid"),
386
- type=safer.safe_string(item, "type"),
404
+ account_id="",
405
+ transaction_type=safer.safe_string(item, "type"),
406
+ order_type=safer.safe_string(item, "transaction_type"),
407
+ tr_position="",
408
+ symbol=safer.safe_string(item, "currency"),
409
+ price=1,
410
+ qty=safer.safe_number(item, "amount"),
387
411
  amount=safer.safe_number(item, "amount"),
388
412
  tax=0,
389
413
  fee=safer.safe_number(item, "fee"),
390
414
  currency=safer.safe_string(item, "currency"),
391
- created_at=datetime.fromisoformat(safer.safe_string(item, "created_at")),
415
+ created_at=datetime.fromisoformat(safer.safe_string(item, "done_at")),
392
416
  )