ksxt 0.0.7__py3-none-any.whl → 0.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. ksxt/__init__.py +3 -1
  2. ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
  3. ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
  4. ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
  5. ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
  6. ksxt/api/__init__.py +26 -0
  7. ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
  8. ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
  9. ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
  10. ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
  11. ksxt/api/auto/api_generator.py +54 -0
  12. ksxt/api/auto/bithumb.py +35 -0
  13. ksxt/api/auto/koreainvest.py +49 -0
  14. ksxt/api/auto/upbit.py +39 -0
  15. ksxt/api/bithumb.py +42 -0
  16. ksxt/api/koreainvest.py +40 -0
  17. ksxt/api/upbit.py +54 -0
  18. ksxt/async_/__init__.py +4 -0
  19. ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
  20. ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
  21. ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
  22. ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
  23. ksxt/async_/base/__init__.py +0 -0
  24. ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
  25. ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
  26. ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
  27. ksxt/async_/base/async_exchange.py +232 -0
  28. ksxt/async_/base/throttler.py +63 -0
  29. ksxt/async_/bithumb.py +455 -0
  30. ksxt/async_/koreainvest.py +849 -0
  31. ksxt/async_/upbit.py +488 -0
  32. ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
  33. ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
  34. ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
  35. ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
  36. ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
  37. ksxt/base/com_exchange.py +2 -2
  38. ksxt/base/errors.py +10 -0
  39. ksxt/base/exchange.py +188 -497
  40. ksxt/base/rest_exchange.py +297 -113
  41. ksxt/base/types.py +1 -36
  42. ksxt/bithumb.py +504 -0
  43. ksxt/config/__init__.py +2 -1
  44. ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
  45. ksxt/config/bithumb.toml +380 -0
  46. ksxt/config/koreainvest.toml +312 -0
  47. ksxt/config/token.toml +7 -0
  48. ksxt/config/upbit.toml +428 -0
  49. ksxt/koreainvest.py +409 -1055
  50. ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
  51. ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
  52. ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
  53. ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
  54. ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
  55. ksxt/market/base.py +50 -50
  56. ksxt/market/db.py +5 -4
  57. ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
  58. ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
  59. ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
  60. ksxt/market/krx/kosdaq.py +150 -147
  61. ksxt/market/krx/kospi.py +179 -175
  62. ksxt/market/krx/stock.py +136 -134
  63. ksxt/market/logging.py +4 -4
  64. ksxt/market/manager.py +11 -13
  65. ksxt/market/markets.py +1 -1
  66. ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
  67. ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
  68. ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
  69. ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
  70. ksxt/market/us/amex.py +31 -31
  71. ksxt/market/us/nasdaq.py +31 -31
  72. ksxt/market/us/nyse.py +31 -31
  73. ksxt/market/us/stock.py +20 -28
  74. ksxt/models/__init__.py +16 -0
  75. ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
  76. ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
  77. ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
  78. ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
  79. ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
  80. ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
  81. ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
  82. ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
  83. ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
  84. ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
  85. ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
  86. ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
  87. ksxt/models/balance.py +30 -0
  88. ksxt/models/cash.py +15 -0
  89. ksxt/models/common.py +31 -0
  90. ksxt/models/error.py +13 -0
  91. ksxt/models/historical.py +26 -0
  92. ksxt/models/market.py +81 -0
  93. ksxt/models/order.py +42 -0
  94. ksxt/models/orderbook.py +32 -0
  95. ksxt/models/ticker.py +25 -0
  96. ksxt/models/token.py +14 -0
  97. ksxt/models/transaction.py +79 -0
  98. ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
  99. ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
  100. ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
  101. ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
  102. ksxt/parser/bithumb.py +300 -0
  103. ksxt/parser/koreainvest.py +323 -0
  104. ksxt/parser/parser.py +114 -0
  105. ksxt/parser/upbit.py +308 -0
  106. ksxt/upbit.py +499 -0
  107. ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
  108. ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
  109. ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
  110. ksxt/utils/safer.py +48 -0
  111. ksxt/utils/sorter.py +8 -0
  112. ksxt/utils/timer.py +47 -0
  113. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/METADATA +11 -1
  114. ksxt-0.0.9.dist-info/RECORD +119 -0
  115. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/WHEEL +1 -1
  116. ksxt/__pycache__/__init__.cpython-39.pyc +0 -0
  117. ksxt/__pycache__/koreainvest.cpython-39.pyc +0 -0
  118. ksxt/base/__pycache__/__init__.cpython-39.pyc +0 -0
  119. ksxt/base/__pycache__/exchange.cpython-39.pyc +0 -0
  120. ksxt/base/__pycache__/rest_exchange.cpython-39.pyc +0 -0
  121. ksxt/base/__pycache__/restexchange.cpython-39.pyc +0 -0
  122. ksxt/base/__pycache__/types.cpython-39.pyc +0 -0
  123. ksxt/base/api_response.py +0 -68
  124. ksxt/config/__pycache__/__init__.cpython-39.pyc +0 -0
  125. ksxt/config/tr_app.json +0 -381
  126. ksxt/config/tr_dev.json +0 -446
  127. ksxt/market/__pycache__/base.cpython-39.pyc +0 -0
  128. ksxt/market/__pycache__/db.cpython-39.pyc +0 -0
  129. ksxt/market/__pycache__/logging.cpython-39.pyc +0 -0
  130. ksxt/market/__pycache__/manager.cpython-39.pyc +0 -0
  131. ksxt/market/__pycache__/markets.cpython-39.pyc +0 -0
  132. ksxt/market/krx/__pycache__/kosdaq.cpython-39.pyc +0 -0
  133. ksxt/market/krx/__pycache__/kospi.cpython-39.pyc +0 -0
  134. ksxt/market/krx/__pycache__/stock.cpython-39.pyc +0 -0
  135. ksxt/market/us/__pycache__/amex.cpython-39.pyc +0 -0
  136. ksxt/market/us/__pycache__/nasdaq.cpython-39.pyc +0 -0
  137. ksxt/market/us/__pycache__/nyse.cpython-39.pyc +0 -0
  138. ksxt/market/us/__pycache__/stock.cpython-39.pyc +0 -0
  139. ksxt-0.0.7.dist-info/RECORD +0 -49
  140. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/LICENSE.txt +0 -0
  141. {ksxt-0.0.7.dist-info → ksxt-0.0.9.dist-info}/top_level.txt +0 -0
ksxt/models/token.py ADDED
@@ -0,0 +1,14 @@
1
+ from datetime import datetime
2
+ from pydantic import BaseModel
3
+ from ksxt.models.common import GeneralResponse
4
+
5
+
6
+ class TokenInfo(BaseModel):
7
+ access_token: str
8
+ token_type: str
9
+ remain_time_second: float
10
+ expired_datetime: datetime
11
+
12
+
13
+ class KsxtTokenResponse(GeneralResponse[TokenInfo]):
14
+ pass
@@ -0,0 +1,79 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+ from pydantic import BaseModel
4
+
5
+ from ksxt.models.common import GeneralResponse
6
+
7
+
8
+ class TransactionInfo(BaseModel):
9
+ # 주문 고유 아이디
10
+ uuid: str
11
+ # 주문 종류 (ask, bid, deposit, withdrawal)
12
+ type: str
13
+
14
+ # 금액
15
+ amount: float
16
+ # 수수료
17
+ fee: Optional[float] = 0
18
+
19
+ # 계좌 번호
20
+ account_id: Optional[str] = None
21
+ # 화폐 통화 정보
22
+ currency: Optional[str] = None
23
+
24
+ # 주문 생성 시간
25
+ created_at: datetime
26
+
27
+
28
+ class OpenedOrderInfo(TransactionInfo):
29
+ # 종목 정보
30
+ symbol: str
31
+ # 가격
32
+ price: float
33
+ # 수량
34
+ qty: float
35
+ # 주문 방식
36
+ order_type: Optional[str]
37
+
38
+
39
+ class ClosedOrderInfo(TransactionInfo):
40
+ # 종목 정보
41
+ symbol: str
42
+ # 가격
43
+ price: float
44
+ # 수량
45
+ qty: float
46
+ # 주문 방식
47
+ order_type: Optional[str]
48
+
49
+
50
+ class WithdrawalHistory(BaseModel):
51
+ history: List[TransactionInfo]
52
+
53
+
54
+ class DepositHistory(BaseModel):
55
+ history: List[TransactionInfo]
56
+
57
+
58
+ class OpenedOrderHistory(BaseModel):
59
+ history: List[OpenedOrderInfo]
60
+
61
+
62
+ class ClosedOrderHistory(BaseModel):
63
+ history: List[ClosedOrderInfo]
64
+
65
+
66
+ class KsxtWithdrawalHistoryResponse(GeneralResponse[WithdrawalHistory]):
67
+ pass
68
+
69
+
70
+ class KsxtDepositHistoryResponse(GeneralResponse[DepositHistory]):
71
+ pass
72
+
73
+
74
+ class KsxtOpenOrderResponse(GeneralResponse[OpenedOrderHistory]):
75
+ pass
76
+
77
+
78
+ class KsxtClosedOrderResponse(GeneralResponse[ClosedOrderHistory]):
79
+ pass
ksxt/parser/bithumb.py ADDED
@@ -0,0 +1,300 @@
1
+ from datetime import datetime
2
+ from operator import attrgetter
3
+ from typing import Dict, List
4
+
5
+ from ksxt.models.transaction import (
6
+ ClosedOrderHistory,
7
+ ClosedOrderInfo,
8
+ DepositHistory,
9
+ OpenedOrderHistory,
10
+ OpenedOrderInfo,
11
+ TransactionInfo,
12
+ WithdrawalHistory,
13
+ )
14
+ from ksxt.models.balance import BalanceData, BalanceInfo
15
+ from ksxt.models.cash import CashInfo
16
+ from ksxt.models.historical import HistoricalDataInfo, OHLCVData
17
+ from ksxt.models.market import MarketInfo, SecurityData, TradeFeeInfo
18
+ from ksxt.models.order import CancelOrderResponse, CreateOrderResponse
19
+ from ksxt.models.orderbook import MultiSymbolOrderBookInfos, OrderBookData, OrderBookInfo
20
+ from ksxt.models.ticker import MultiSymbolTickerInfo, TickerInfo
21
+ from ksxt.parser.parser import BaseParser
22
+ from ksxt.utils import safer, sorter
23
+
24
+
25
+ class BithumbParser(BaseParser):
26
+ def safe_symbol(self, base_market: str, security: str) -> str:
27
+ return f"{base_market}-{security}"
28
+
29
+ def parse_markets(self, response: List[Dict], base_market: str = "KRW") -> MarketInfo:
30
+ securities = {}
31
+ for market in response:
32
+ market_base = market["market"].split("-")[0]
33
+ if market_base != base_market:
34
+ continue
35
+
36
+ security_data = self._parse_market(market)
37
+ securities[security_data.symbol] = security_data
38
+
39
+ return MarketInfo(market_id=base_market, securities=securities)
40
+
41
+ def _parse_market(self, market: Dict) -> SecurityData:
42
+ return SecurityData(
43
+ symbol=safer.safe_string(market, "market"),
44
+ name=safer.safe_string(market, "korean_name"),
45
+ type="crypto",
46
+ warning_code=False if safer.safe_string(market, "market_warning") == "NONE" else True,
47
+ )
48
+
49
+ def parse_historical_data(self, response: dict, symbol: str, base_market: str = "KRW") -> HistoricalDataInfo:
50
+ ohlcv = [self._parse_ohlcva(_, base_market) for _ in response]
51
+ sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
52
+
53
+ security_name = symbol
54
+
55
+ result = HistoricalDataInfo(
56
+ symbol=self.safe_symbol(base_market, security_name), security_name=security_name, history=sorted_ohlcv
57
+ )
58
+
59
+ return result
60
+
61
+ def _parse_ohlcva(self, ohlcva: dict, base_market: str = "KRW") -> OHLCVData:
62
+ fmt = "%Y-%m-%dT%H:%M:%S"
63
+ return OHLCVData(
64
+ datetime=datetime.strptime(safer.safe_string(ohlcva, "candle_date_time_kst"), fmt),
65
+ open_price=safer.safe_number(ohlcva, "opening_price"),
66
+ high_price=safer.safe_number(ohlcva, "high_price"),
67
+ low_price=safer.safe_number(ohlcva, "low_price"),
68
+ close_price=safer.safe_number(ohlcva, "trade_price"),
69
+ acml_volume=safer.safe_number(ohlcva, "candle_acc_trade_volume"),
70
+ acml_amount=safer.safe_number(ohlcva, "candle_acc_trade_price"),
71
+ )
72
+
73
+ def parse_ticker(self, response: List[Dict], base_market: str = "KRW") -> TickerInfo:
74
+ ticker_info = self._parse_ticker(response[0], base_market=base_market)
75
+ return ticker_info
76
+
77
+ def parse_tickers(self, response: List[Dict], base_market: str = "KRW") -> MultiSymbolTickerInfo:
78
+ tickers_info = {}
79
+
80
+ for ticker_data in response:
81
+ symbol = safer.safe_string(ticker_data, "market")
82
+ ticker_info = self._parse_ticker(ticker_data, base_market)
83
+ tickers_info[symbol] = ticker_info
84
+
85
+ return MultiSymbolTickerInfo(tickers=tickers_info)
86
+
87
+ def _parse_ticker(self, response: dict, base_market: str) -> TickerInfo:
88
+ timestamp_ms = safer.safe_number(response, "timestamp")
89
+ timestamp_s = timestamp_ms / 1000.0
90
+
91
+ return TickerInfo(
92
+ symbol=safer.safe_string(response, "market"),
93
+ price=safer.safe_number(response, "trade_price"),
94
+ ts=datetime.fromtimestamp(timestamp_s),
95
+ )
96
+
97
+ def parse_orderbook(self, response: List[Dict], base_market: str = "KRW") -> OrderBookInfo:
98
+ ask_list = []
99
+ bid_list = []
100
+
101
+ for item in response:
102
+ for index, data in enumerate(item["orderbook_units"]):
103
+ ask_data, bid_data = self._parse_orderbook(data, index, base_market)
104
+ ask_list.append(ask_data)
105
+ bid_list.append(bid_data)
106
+
107
+ return OrderBookInfo(
108
+ total_asks_qty=safer.safe_string(response[0], "total_ask_size"),
109
+ total_bids_qty=safer.safe_string(response[0], "total_bid_size"),
110
+ asks=ask_list,
111
+ bids=bid_list,
112
+ )
113
+
114
+ def parse_orderbooks(self, response: dict, base_market: str) -> MultiSymbolOrderBookInfos:
115
+ order_books = {}
116
+
117
+ # response에서 'order_books' 항목이 리스트 형태로 되어 있다고 가정
118
+ for symbol_info in response:
119
+ symbol = symbol_info["market"] # 각 종목의 심볼 추출
120
+ orderbook_units = symbol_info["orderbook_units"] # 호가 정보 추출
121
+
122
+ ask_list = []
123
+ bid_list = []
124
+
125
+ for index, data in enumerate(orderbook_units):
126
+ ask_data, bid_data = self._parse_orderbook(data, index, base_market)
127
+ ask_list.append(ask_data)
128
+ bid_list.append(bid_data)
129
+
130
+ # OrderBookInfo 객체 생성
131
+ order_book_info = OrderBookInfo(
132
+ total_asks_qty=safer.safe_number(symbol_info, "total_ask_size"),
133
+ total_bids_qty=safer.safe_number(symbol_info, "total_bid_size"),
134
+ asks=ask_list,
135
+ bids=bid_list,
136
+ )
137
+
138
+ # 심볼과 함께 OrderBookInfo를 딕셔너리에 추가
139
+ order_books[symbol] = order_book_info
140
+
141
+ # MultiSymbolOrderBookInfo 객체 반환
142
+ return MultiSymbolOrderBookInfos(order_books=order_books)
143
+
144
+ def _parse_orderbook(
145
+ self, orderbook: dict, index: int, base_market: str = "KRW"
146
+ ) -> tuple[OrderBookData, OrderBookData]:
147
+ ask_data = OrderBookData(
148
+ side="ask",
149
+ ob_num=index,
150
+ ob_price=safer.safe_number(orderbook, "ask_price"),
151
+ ob_qty=safer.safe_number(orderbook, "ask_size"),
152
+ )
153
+
154
+ bid_data = OrderBookData(
155
+ side="bid",
156
+ ob_num=index,
157
+ ob_price=safer.safe_number(orderbook, "bid_price"),
158
+ ob_qty=safer.safe_number(orderbook, "bid_size"),
159
+ )
160
+
161
+ return ask_data, bid_data
162
+
163
+ def parse_balance(self, response: List[Dict], base_market: str = "KRW") -> BalanceInfo:
164
+ # currency가 'KRW'가 아닌 항목만 필터링
165
+ filtered_data = [data for data in response if data["currency"] != base_market]
166
+
167
+ # Initialize balance list
168
+ balances = [self._parse_balance(data, base_market) for data in filtered_data]
169
+
170
+ # 총 매입금액
171
+ total_amount = sum(bal.price * bal.qty for bal in balances)
172
+ total_evaluation_amount = sum(bal.evaluation_price * bal.qty for bal in balances)
173
+ total_pnl_amount = total_evaluation_amount - total_amount
174
+ total_pnl_ratio = (total_pnl_amount / total_amount * 100) if total_amount != 0 else 0
175
+
176
+ return BalanceInfo(
177
+ currency=base_market,
178
+ total_amount=total_amount,
179
+ total_evaluation_amount=total_amount,
180
+ total_pnl_amount=total_pnl_amount,
181
+ total_pnl_ratio=total_pnl_ratio,
182
+ balances=balances,
183
+ )
184
+
185
+ def _parse_balance(self, data: Dict, base_market: str = "KRW") -> BalanceData:
186
+ return BalanceData(
187
+ symbol=self.safe_symbol(base_market, safer.safe_string(data, "currency")),
188
+ name=self.safe_symbol(base_market, safer.safe_string(data, "currency")),
189
+ evaluation_price=0, # 필요에 따라 적절히 설정
190
+ price=safer.safe_number(data, "avg_buy_price"),
191
+ pnl_amount=0, # 필요에 따라 적절히 설정
192
+ pnl_ratio=0, # 필요에 따라 적절히 설정
193
+ qty=safer.safe_number(data, "balance"),
194
+ free_qty=safer.safe_number(data, "balance") - safer.safe_number(data, "locked"),
195
+ used_qty=safer.safe_number(data, "locked"),
196
+ )
197
+
198
+ def parse_cash(self, response: List[Dict], base_market: str = "KRW") -> CashInfo:
199
+ # currency가 'KRW'인 항목만 필터링
200
+ filtered_data = [data for data in response if data["currency"] == base_market]
201
+
202
+ # 필터링된 데이터가 없으면 기본값으로 CashInfo 반환
203
+ if not filtered_data:
204
+ return CashInfo(currency=base_market, cash=0.0, cash_d1=0.0, cash_d2=0.0)
205
+
206
+ # 필터링된 첫 번째 항목을 가져와서 CashInfo 생성
207
+ data = filtered_data[0]
208
+
209
+ return CashInfo(
210
+ currency=base_market,
211
+ cash=safer.safe_number(data, "balance"),
212
+ cash_d1=safer.safe_number(data, "balance"), # 데이터를 가정하여 같은 값 사용
213
+ cash_d2=safer.safe_number(data, "balance"), # 데이터를 가정하여 같은 값 사용
214
+ )
215
+
216
+ def parse_security(self, response: dict, base_market: str = "KRW") -> SecurityData:
217
+ market_info = response.get("market", {})
218
+
219
+ return SecurityData(
220
+ symbol=safer.safe_string(market_info, "id"),
221
+ name=safer.safe_string(market_info, "name"),
222
+ type="crypto",
223
+ bid_qty_unit=safer.safe_number(market_info["bid"], "price_unit"),
224
+ ask_qty_unit=safer.safe_number(market_info["ask"], "price_unit"),
225
+ bid_min_qty=safer.safe_number(market_info["bid"], "min_total"),
226
+ ask_min_qty=safer.safe_number(market_info["ask"], "min_total"),
227
+ bid_max_qty=safer.safe_number(market_info, "max_total"),
228
+ ask_max_qty=safer.safe_number(market_info, "max_total"),
229
+ bid_min_amount=safer.safe_number(market_info["bid"], "min_total"),
230
+ ask_min_amount=safer.safe_number(market_info["ask"], "min_total"),
231
+ bid_max_amount=safer.safe_number(market_info, "max_total"),
232
+ ask_max_amount=safer.safe_number(market_info, "max_total"),
233
+ warning_code=safer.safe_string(market_info, "state") != "active",
234
+ )
235
+
236
+ def parse_trade_fee(self, response: dict, base_market: str = "KRW") -> TradeFeeInfo:
237
+ return TradeFeeInfo(
238
+ limit_bid_fee=safer.safe_number(response, "bid_fee"),
239
+ limit_ask_fee=safer.safe_number(response, "ask_fee"),
240
+ market_bid_fee=safer.safe_number(response, "maker_bid_fee"),
241
+ market_ask_fee=safer.safe_number(response, "maker_ask_fee"),
242
+ )
243
+
244
+ def parse_open_order_history(self, response: dict, base_market: str = "KRW") -> OpenedOrderHistory:
245
+ orders = [self._parse_open_order_info(order, base_market) for order in response]
246
+ return OpenedOrderHistory(history=orders)
247
+
248
+ def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
249
+ return OpenedOrderInfo(
250
+ uuid=safer.safe_string(order, "uuid"),
251
+ type=safer.safe_string(order, "side"),
252
+ symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
253
+ price=safer.safe_number(order, "price"),
254
+ qty=safer.safe_number(order, "volume"),
255
+ amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
256
+ fee=safer.safe_number(order, "reserved_fee"),
257
+ created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
258
+ order_type=safer.safe_string(order, "ord_type"),
259
+ )
260
+
261
+ def parse_closed_order_history(self, response: dict, base_market: str = "KRW") -> ClosedOrderHistory:
262
+ orders = [self._parse_closed_order_info(order, base_market) for order in response]
263
+ return ClosedOrderHistory(history=orders)
264
+
265
+ def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
266
+ return ClosedOrderInfo(
267
+ uuid=safer.safe_string(order, "uuid"),
268
+ type=safer.safe_string(order, "side"),
269
+ symbol=safer.safe_string(order, "market"),
270
+ price=safer.safe_number(order, "price"),
271
+ qty=safer.safe_number(order, "volume"),
272
+ amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
273
+ fee=safer.safe_number(order, "reserved_fee"),
274
+ created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
275
+ order_type=safer.safe_string(order, "ord_type"),
276
+ )
277
+
278
+ def parse_cancel_order(self, response: dict, base_market: str = "KRW") -> CancelOrderResponse:
279
+ return CancelOrderResponse(order_datetime=datetime.now(), order_id=safer.safe_string(response, "uuid"))
280
+
281
+ def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
282
+ return CreateOrderResponse(order_datetime=datetime.now(), order_id=safer.safe_string(response, "uuid"))
283
+
284
+ def parse_withdrawal_history(self, response: List[Dict], base_market: str = "KRW") -> WithdrawalHistory:
285
+ parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
286
+ return WithdrawalHistory(history=parsed_items)
287
+
288
+ def parse_deposit_history(self, response: List[Dict], base_market: str = "KRW") -> DepositHistory:
289
+ parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
290
+ return DepositHistory(history=parsed_items)
291
+
292
+ def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
293
+ return TransactionInfo(
294
+ uuid=safer.safe_string(item, "uuid"),
295
+ type=safer.safe_string(item, "type"),
296
+ amount=safer.safe_number(item, "amount"),
297
+ fee=safer.safe_number(item, "fee"),
298
+ currency=safer.safe_string(item, "currency"),
299
+ created_at=datetime.fromisoformat(safer.safe_string(item, "created_at")),
300
+ )