ksxt 0.0.8__py3-none-any.whl → 0.0.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ksxt/__init__.py +3 -1
- ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/api/__init__.py +26 -0
- ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/api/auto/api_generator.py +54 -0
- ksxt/api/auto/bithumb.py +35 -0
- ksxt/api/auto/koreainvest.py +49 -0
- ksxt/api/auto/upbit.py +39 -0
- ksxt/api/bithumb.py +42 -0
- ksxt/api/koreainvest.py +40 -0
- ksxt/api/upbit.py +54 -0
- ksxt/async_/__init__.py +4 -0
- ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/async_/base/__init__.py +0 -0
- ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
- ksxt/async_/base/async_exchange.py +232 -0
- ksxt/async_/base/throttler.py +63 -0
- ksxt/async_/bithumb.py +455 -0
- ksxt/async_/koreainvest.py +849 -0
- ksxt/async_/upbit.py +488 -0
- ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
- ksxt/base/com_exchange.py +2 -2
- ksxt/base/errors.py +10 -0
- ksxt/base/exchange.py +188 -497
- ksxt/base/rest_exchange.py +297 -113
- ksxt/base/types.py +1 -36
- ksxt/bithumb.py +504 -0
- ksxt/config/__init__.py +2 -1
- ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/config/bithumb.toml +380 -0
- ksxt/config/koreainvest.toml +312 -0
- ksxt/config/token.toml +7 -0
- ksxt/config/upbit.toml +428 -0
- ksxt/koreainvest.py +409 -1055
- ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
- ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
- ksxt/market/base.py +50 -50
- ksxt/market/db.py +5 -4
- ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
- ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
- ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
- ksxt/market/krx/kosdaq.py +150 -147
- ksxt/market/krx/kospi.py +179 -175
- ksxt/market/krx/stock.py +136 -134
- ksxt/market/logging.py +4 -4
- ksxt/market/manager.py +10 -12
- ksxt/market/markets.py +1 -1
- ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
- ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
- ksxt/market/us/amex.py +31 -31
- ksxt/market/us/nasdaq.py +31 -31
- ksxt/market/us/nyse.py +31 -31
- ksxt/market/us/stock.py +20 -28
- ksxt/models/__init__.py +16 -0
- ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
- ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
- ksxt/models/balance.py +30 -0
- ksxt/models/cash.py +15 -0
- ksxt/models/common.py +31 -0
- ksxt/models/error.py +13 -0
- ksxt/models/historical.py +26 -0
- ksxt/models/market.py +81 -0
- ksxt/models/order.py +42 -0
- ksxt/models/orderbook.py +32 -0
- ksxt/models/ticker.py +25 -0
- ksxt/models/token.py +14 -0
- ksxt/models/transaction.py +79 -0
- ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
- ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
- ksxt/parser/bithumb.py +300 -0
- ksxt/parser/koreainvest.py +323 -0
- ksxt/parser/parser.py +114 -0
- ksxt/parser/upbit.py +308 -0
- ksxt/upbit.py +499 -0
- ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
- ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
- ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
- ksxt/utils/safer.py +48 -0
- ksxt/utils/sorter.py +8 -0
- ksxt/utils/timer.py +47 -0
- {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/METADATA +11 -1
- ksxt-0.0.10.dist-info/RECORD +119 -0
- {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/WHEEL +1 -1
- ksxt/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/__pycache__/koreainvest.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/exchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/restexchange.cpython-39.pyc +0 -0
- ksxt/base/__pycache__/types.cpython-39.pyc +0 -0
- ksxt/base/api_response.py +0 -68
- ksxt/config/__pycache__/__init__.cpython-39.pyc +0 -0
- ksxt/config/tr_app.json +0 -381
- ksxt/config/tr_dev.json +0 -446
- ksxt/market/__pycache__/base.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/db.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/logging.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/manager.cpython-39.pyc +0 -0
- ksxt/market/__pycache__/markets.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/kosdaq.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/kospi.cpython-39.pyc +0 -0
- ksxt/market/krx/__pycache__/stock.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/amex.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/nasdaq.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/nyse.cpython-39.pyc +0 -0
- ksxt/market/us/__pycache__/stock.cpython-39.pyc +0 -0
- ksxt-0.0.8.dist-info/RECORD +0 -49
- {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/LICENSE.txt +0 -0
- {ksxt-0.0.8.dist-info → ksxt-0.0.10.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
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
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
|
+
)
|