ksxt 1.0.3__py3-none-any.whl → 1.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/__pycache__/upbit.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/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/__pycache__/async_exchange.cpython-312.pyc +0 -0
- ksxt/async_/base/async_exchange.py +19 -17
- ksxt/async_/bithumb.py +41 -21
- ksxt/async_/koreainvest.py +80 -8
- ksxt/async_/upbit.py +58 -22
- ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
- ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
- ksxt/base/exchange.py +33 -66
- ksxt/base/rest_exchange.py +28 -29
- ksxt/bithumb.py +33 -14
- ksxt/koreainvest.py +30 -8
- ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
- ksxt/models/transaction.py +2 -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 +102 -12
- ksxt/parser/koreainvest.py +66 -12
- ksxt/parser/parser.py +25 -7
- ksxt/parser/upbit.py +106 -16
- ksxt/upbit.py +48 -18
- {ksxt-1.0.3.dist-info → ksxt-1.0.5.dist-info}/METADATA +1 -1
- {ksxt-1.0.3.dist-info → ksxt-1.0.5.dist-info}/RECORD +36 -36
- {ksxt-1.0.3.dist-info → ksxt-1.0.5.dist-info}/WHEEL +1 -1
- {ksxt-1.0.3.dist-info → ksxt-1.0.5.dist-info}/LICENSE.txt +0 -0
- {ksxt-1.0.3.dist-info → ksxt-1.0.5.dist-info}/top_level.txt +0 -0
ksxt/parser/bithumb.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
from datetime import datetime
|
1
|
+
from datetime import datetime, timezone
|
2
2
|
from operator import attrgetter
|
3
|
-
from typing import Dict, List
|
3
|
+
from typing import Dict, List, Optional
|
4
4
|
|
5
5
|
from ksxt.models.transaction import (
|
6
6
|
ClosedOrderHistory,
|
@@ -46,8 +46,22 @@ class BithumbParser(BaseParser):
|
|
46
46
|
warning_code=False if safer.safe_string(market, "market_warning") == "NONE" else True,
|
47
47
|
)
|
48
48
|
|
49
|
-
def parse_historical_data(
|
49
|
+
def parse_historical_data(
|
50
|
+
self,
|
51
|
+
response: List[Dict],
|
52
|
+
symbol: str,
|
53
|
+
start: datetime | None = None,
|
54
|
+
end: datetime | None = None,
|
55
|
+
base_market: str = "KRW",
|
56
|
+
) -> HistoricalDataInfo:
|
50
57
|
ohlcv = [self._parse_ohlcva(_, base_market) for _ in response]
|
58
|
+
|
59
|
+
# Filter by start and end datetime
|
60
|
+
if start:
|
61
|
+
ohlcv = [data for data in ohlcv if data.datetime >= start]
|
62
|
+
if end:
|
63
|
+
ohlcv = [data for data in ohlcv if data.datetime <= end]
|
64
|
+
|
51
65
|
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
52
66
|
|
53
67
|
security_name = symbol
|
@@ -160,9 +174,19 @@ class BithumbParser(BaseParser):
|
|
160
174
|
|
161
175
|
return ask_data, bid_data
|
162
176
|
|
163
|
-
def parse_balance(
|
164
|
-
|
165
|
-
|
177
|
+
def parse_balance(
|
178
|
+
self, response: List[Dict], base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
|
179
|
+
) -> BalanceInfo:
|
180
|
+
# 1. Filter out entries where 'currency' is not the base_market
|
181
|
+
# 2. Ensure 'unit_currency' is the base_market
|
182
|
+
# 3. Exclude entries where 'currency' is in excluded_symbols
|
183
|
+
filtered_data = [
|
184
|
+
data
|
185
|
+
for data in response
|
186
|
+
if data["currency"] != base_market
|
187
|
+
and data["unit_currency"] == base_market
|
188
|
+
and (excluded_symbols is None or data["currency"] not in excluded_symbols)
|
189
|
+
]
|
166
190
|
|
167
191
|
# Initialize balance list
|
168
192
|
balances = [self._parse_balance(data, base_market) for data in filtered_data]
|
@@ -196,8 +220,11 @@ class BithumbParser(BaseParser):
|
|
196
220
|
)
|
197
221
|
|
198
222
|
def parse_cash(self, response: List[Dict], base_market: str = "KRW") -> CashInfo:
|
199
|
-
#
|
200
|
-
|
223
|
+
# 1. Filter entries where 'currency' is equal to 'base_market'
|
224
|
+
# 2. Ensure 'unit_currency' is also equal to 'base_market'
|
225
|
+
filtered_data = [
|
226
|
+
data for data in response if data["currency"] == base_market and data["unit_currency"] == base_market
|
227
|
+
]
|
201
228
|
|
202
229
|
# 필터링된 데이터가 없으면 기본값으로 CashInfo 반환
|
203
230
|
if not filtered_data:
|
@@ -243,8 +270,21 @@ class BithumbParser(BaseParser):
|
|
243
270
|
market_ask_fee=safer.safe_number(response, "maker_ask_fee"),
|
244
271
|
)
|
245
272
|
|
246
|
-
def parse_open_order_history(
|
273
|
+
def parse_open_order_history(
|
274
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
275
|
+
) -> OpenedOrderHistory:
|
247
276
|
orders = [self._parse_open_order_info(order, base_market) for order in response]
|
277
|
+
|
278
|
+
# Filter by start and end datetime
|
279
|
+
if start:
|
280
|
+
orders = [
|
281
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
282
|
+
]
|
283
|
+
if end:
|
284
|
+
orders = [
|
285
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
286
|
+
]
|
287
|
+
|
248
288
|
return OpenedOrderHistory(history=orders)
|
249
289
|
|
250
290
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
@@ -255,13 +295,27 @@ class BithumbParser(BaseParser):
|
|
255
295
|
price=safer.safe_number(order, "price"),
|
256
296
|
qty=safer.safe_number(order, "volume"),
|
257
297
|
amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
|
298
|
+
tax=0,
|
258
299
|
fee=safer.safe_number(order, "reserved_fee"),
|
259
300
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
260
301
|
order_type=safer.safe_string(order, "ord_type"),
|
261
302
|
)
|
262
303
|
|
263
|
-
def parse_closed_order_history(
|
304
|
+
def parse_closed_order_history(
|
305
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
306
|
+
) -> ClosedOrderHistory:
|
264
307
|
orders = [self._parse_closed_order_info(order, base_market) for order in response]
|
308
|
+
|
309
|
+
# Filter by start and end datetime
|
310
|
+
if start:
|
311
|
+
orders = [
|
312
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
313
|
+
]
|
314
|
+
if end:
|
315
|
+
orders = [
|
316
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
317
|
+
]
|
318
|
+
|
265
319
|
return ClosedOrderHistory(history=orders)
|
266
320
|
|
267
321
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -272,6 +326,7 @@ class BithumbParser(BaseParser):
|
|
272
326
|
price=safer.safe_number(order, "price"),
|
273
327
|
qty=safer.safe_number(order, "volume"),
|
274
328
|
amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
|
329
|
+
tax=0,
|
275
330
|
fee=safer.safe_number(order, "reserved_fee"),
|
276
331
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
277
332
|
order_type=safer.safe_string(order, "ord_type"),
|
@@ -283,12 +338,46 @@ class BithumbParser(BaseParser):
|
|
283
338
|
def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
|
284
339
|
return CreateOrderResponse(order_datetime=datetime.now(), order_id=safer.safe_string(response, "uuid"))
|
285
340
|
|
286
|
-
def parse_withdrawal_history(
|
341
|
+
def parse_withdrawal_history(
|
342
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
343
|
+
) -> WithdrawalHistory:
|
287
344
|
parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
|
345
|
+
|
346
|
+
# Filter by start and end datetime
|
347
|
+
if start:
|
348
|
+
parsed_items = [
|
349
|
+
item
|
350
|
+
for item in parsed_items
|
351
|
+
if item.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
352
|
+
]
|
353
|
+
if end:
|
354
|
+
parsed_items = [
|
355
|
+
item
|
356
|
+
for item in parsed_items
|
357
|
+
if item.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
358
|
+
]
|
359
|
+
|
288
360
|
return WithdrawalHistory(history=parsed_items)
|
289
361
|
|
290
|
-
def parse_deposit_history(
|
362
|
+
def parse_deposit_history(
|
363
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
364
|
+
) -> DepositHistory:
|
291
365
|
parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
|
366
|
+
|
367
|
+
# Filter by start and end datetime
|
368
|
+
if start:
|
369
|
+
parsed_items = [
|
370
|
+
item
|
371
|
+
for item in parsed_items
|
372
|
+
if item.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
373
|
+
]
|
374
|
+
if end:
|
375
|
+
parsed_items = [
|
376
|
+
item
|
377
|
+
for item in parsed_items
|
378
|
+
if item.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
379
|
+
]
|
380
|
+
|
292
381
|
return DepositHistory(history=parsed_items)
|
293
382
|
|
294
383
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
@@ -296,6 +385,7 @@ class BithumbParser(BaseParser):
|
|
296
385
|
uuid=safer.safe_string(item, "uuid"),
|
297
386
|
type=safer.safe_string(item, "type"),
|
298
387
|
amount=safer.safe_number(item, "amount"),
|
388
|
+
tax=0,
|
299
389
|
fee=safer.safe_number(item, "fee"),
|
300
390
|
currency=safer.safe_string(item, "currency"),
|
301
391
|
created_at=datetime.fromisoformat(safer.safe_string(item, "created_at")),
|
ksxt/parser/koreainvest.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from datetime import datetime
|
2
|
-
from typing import Dict, List
|
2
|
+
from typing import Dict, List, Optional
|
3
3
|
|
4
4
|
from ksxt.models.balance import BalanceData, BalanceInfo
|
5
5
|
from ksxt.models.cash import CashInfo
|
@@ -52,9 +52,23 @@ class KoreaInvestParser(BaseParser):
|
|
52
52
|
warning_code=safer.safe_boolean(market, " market_warning"),
|
53
53
|
)
|
54
54
|
|
55
|
-
def parse_historical_data(
|
55
|
+
def parse_historical_data(
|
56
|
+
self,
|
57
|
+
response: List[Dict],
|
58
|
+
symbol: str,
|
59
|
+
start: datetime | None = None,
|
60
|
+
end: datetime | None = None,
|
61
|
+
base_market: str = "KRW",
|
62
|
+
) -> HistoricalDataInfo:
|
56
63
|
safe_response = safer.safe_value(response, "output2")
|
57
64
|
ohlcv = [self._parse_ohlcva(_, base_market) for _ in safe_response]
|
65
|
+
|
66
|
+
# Filter by start and end datetime
|
67
|
+
if start:
|
68
|
+
ohlcv = [data for data in ohlcv if data.datetime >= start]
|
69
|
+
if end:
|
70
|
+
ohlcv = [data for data in ohlcv if data.datetime <= end]
|
71
|
+
|
58
72
|
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
59
73
|
|
60
74
|
security_name = symbol
|
@@ -77,9 +91,23 @@ class KoreaInvestParser(BaseParser):
|
|
77
91
|
acml_amount=safer.safe_number(ohlcva, "acml_tr_pbmn"),
|
78
92
|
)
|
79
93
|
|
80
|
-
def parse_historical_index_data(
|
94
|
+
def parse_historical_index_data(
|
95
|
+
self,
|
96
|
+
response: Dict,
|
97
|
+
symbol: str,
|
98
|
+
start: datetime | None = None,
|
99
|
+
end: datetime | None = None,
|
100
|
+
base_market: str = "KRW",
|
101
|
+
) -> HistoricalDataInfo:
|
81
102
|
safe_response = safer.safe_value(response, "output2")
|
82
103
|
ohlcv = [self._parse_index_ohlcva(_, base_market) for _ in safe_response]
|
104
|
+
|
105
|
+
# Filter by start and end datetime
|
106
|
+
if start:
|
107
|
+
ohlcv = [data for data in ohlcv if data.datetime >= start]
|
108
|
+
if end:
|
109
|
+
ohlcv = [data for data in ohlcv if data.datetime <= end]
|
110
|
+
|
83
111
|
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
84
112
|
|
85
113
|
security_name = symbol
|
@@ -153,11 +181,17 @@ class KoreaInvestParser(BaseParser):
|
|
153
181
|
|
154
182
|
return ask_data, bid_data
|
155
183
|
|
156
|
-
def parse_balance(
|
184
|
+
def parse_balance(
|
185
|
+
self, response: List[Dict], base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
|
186
|
+
) -> BalanceInfo:
|
157
187
|
safe_response = safer.safe_value(response, "output1")
|
158
188
|
|
159
|
-
# Initialize balance list
|
160
|
-
balances = [
|
189
|
+
# Initialize balance list with filtering
|
190
|
+
balances = [
|
191
|
+
self._parse_balance(_, base_market)
|
192
|
+
for _ in safe_response
|
193
|
+
if excluded_symbols is None or safer.safe_string(_, "pdno") not in excluded_symbols
|
194
|
+
]
|
161
195
|
|
162
196
|
# 총 매입금액
|
163
197
|
total_amount = sum(bal.price * bal.qty for bal in balances)
|
@@ -236,10 +270,19 @@ class KoreaInvestParser(BaseParser):
|
|
236
270
|
market_ask_fee=0.0140527 + trading_fee,
|
237
271
|
)
|
238
272
|
|
239
|
-
def parse_closed_order_history(
|
273
|
+
def parse_closed_order_history(
|
274
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
275
|
+
) -> ClosedOrderHistory:
|
240
276
|
safe_response = safer.safe_value(response, "output1")
|
241
|
-
|
242
|
-
|
277
|
+
orders = [self._parse_closed_order_info(_, base_market) for _ in safe_response]
|
278
|
+
|
279
|
+
# Filter by start and end datetime
|
280
|
+
if start:
|
281
|
+
orders = [order for order in orders if order.created_at >= start]
|
282
|
+
if end:
|
283
|
+
orders = [order for order in orders if order.created_at <= end]
|
284
|
+
|
285
|
+
return ClosedOrderHistory(history=orders)
|
243
286
|
|
244
287
|
def _parse_closed_order_info(self, order: Dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
245
288
|
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
@@ -254,16 +297,26 @@ class KoreaInvestParser(BaseParser):
|
|
254
297
|
price=safer.safe_number(order, "avg_prvs"),
|
255
298
|
qty=safer.safe_number(order, "tot_ccld_qty"),
|
256
299
|
amount=safer.safe_number(order, "tot_ccld_amt"),
|
300
|
+
tax=0,
|
257
301
|
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
258
302
|
fee=0,
|
259
303
|
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
260
304
|
order_type=safer.safe_string(order, "avg_prvs"),
|
261
305
|
)
|
262
306
|
|
263
|
-
def parse_open_order_history(
|
307
|
+
def parse_open_order_history(
|
308
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
309
|
+
) -> OpenedOrderHistory:
|
264
310
|
safe_response = safer.safe_value(response, "output1")
|
265
|
-
|
266
|
-
|
311
|
+
orders = [self._parse_open_order_info(_, base_market) for _ in safe_response]
|
312
|
+
|
313
|
+
# Filter by start and end datetime
|
314
|
+
if start:
|
315
|
+
orders = [order for order in orders if order.created_at >= start]
|
316
|
+
if end:
|
317
|
+
orders = [order for order in orders if order.created_at <= end]
|
318
|
+
|
319
|
+
return OpenedOrderHistory(history=orders)
|
267
320
|
|
268
321
|
def _parse_open_order_info(self, order: Dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
269
322
|
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
@@ -278,6 +331,7 @@ class KoreaInvestParser(BaseParser):
|
|
278
331
|
price=safer.safe_number(order, "avg_prvs"),
|
279
332
|
qty=safer.safe_number(order, "tot_ccld_qty"),
|
280
333
|
amount=safer.safe_number(order, "tot_ccld_amt"),
|
334
|
+
tax=0,
|
281
335
|
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
282
336
|
fee=0,
|
283
337
|
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
ksxt/parser/parser.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Dict, List, Optional
|
2
3
|
import inspect
|
3
4
|
|
4
5
|
from ksxt.models.balance import BalanceData, BalanceInfo
|
@@ -30,7 +31,14 @@ class BaseParser:
|
|
30
31
|
def _parse_market(self, market: Dict) -> SecurityData:
|
31
32
|
self._raise_not_implemented_error()
|
32
33
|
|
33
|
-
def parse_historical_data(
|
34
|
+
def parse_historical_data(
|
35
|
+
self,
|
36
|
+
response: List[Dict],
|
37
|
+
symbol: str,
|
38
|
+
start: datetime | None = None,
|
39
|
+
end: datetime | None = None,
|
40
|
+
base_market: str = "KRW",
|
41
|
+
) -> HistoricalDataInfo:
|
34
42
|
self._raise_not_implemented_error()
|
35
43
|
|
36
44
|
def _parse_ohlcva(self, ohlcva: dict, base_market: str = "KRW") -> OHLCVData:
|
@@ -62,7 +70,9 @@ class BaseParser:
|
|
62
70
|
) -> tuple[OrderBookData, OrderBookData]:
|
63
71
|
self._raise_not_implemented_error()
|
64
72
|
|
65
|
-
def parse_balance(
|
73
|
+
def parse_balance(
|
74
|
+
self, response: List[Dict], base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
|
75
|
+
) -> BalanceInfo:
|
66
76
|
self._raise_not_implemented_error()
|
67
77
|
|
68
78
|
def _parse_balance(self, data: Dict, base_market: str = "KRW") -> BalanceData:
|
@@ -77,13 +87,17 @@ class BaseParser:
|
|
77
87
|
def parse_trade_fee(self, response: dict, base_market: str = "KRW") -> TradeFeeInfo:
|
78
88
|
self._raise_not_implemented_error()
|
79
89
|
|
80
|
-
def parse_open_order_history(
|
90
|
+
def parse_open_order_history(
|
91
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
92
|
+
) -> OpenedOrderHistory:
|
81
93
|
self._raise_not_implemented_error()
|
82
94
|
|
83
95
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
84
96
|
self._raise_not_implemented_error()
|
85
97
|
|
86
|
-
def parse_closed_order_history(
|
98
|
+
def parse_closed_order_history(
|
99
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
100
|
+
) -> ClosedOrderHistory:
|
87
101
|
self._raise_not_implemented_error()
|
88
102
|
|
89
103
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -98,10 +112,14 @@ class BaseParser:
|
|
98
112
|
def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
|
99
113
|
self._raise_not_implemented_error()
|
100
114
|
|
101
|
-
def parse_withdrawal_history(
|
115
|
+
def parse_withdrawal_history(
|
116
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
117
|
+
) -> WithdrawalHistory:
|
102
118
|
self._raise_not_implemented_error()
|
103
119
|
|
104
|
-
def parse_deposit_history(
|
120
|
+
def parse_deposit_history(
|
121
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
122
|
+
) -> DepositHistory:
|
105
123
|
self._raise_not_implemented_error()
|
106
124
|
|
107
125
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
ksxt/parser/upbit.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
from datetime import datetime
|
1
|
+
from datetime import datetime, timezone
|
2
2
|
from operator import attrgetter
|
3
|
-
from typing import Dict, List
|
3
|
+
from typing import Dict, List, Optional
|
4
4
|
|
5
5
|
from ksxt.models.balance import BalanceData, BalanceInfo
|
6
6
|
from ksxt.models.cash import CashInfo
|
@@ -56,8 +56,22 @@ class UpbitParser(BaseParser):
|
|
56
56
|
warning_code=safer.safe_boolean(market, " market_warning"),
|
57
57
|
)
|
58
58
|
|
59
|
-
def parse_historical_data(
|
59
|
+
def parse_historical_data(
|
60
|
+
self,
|
61
|
+
response: List[Dict],
|
62
|
+
symbol: str,
|
63
|
+
start: datetime | None = None,
|
64
|
+
end: datetime | None = None,
|
65
|
+
base_market: str = "KRW",
|
66
|
+
) -> HistoricalDataInfo:
|
60
67
|
ohlcv = [self._parse_ohlcva(_, base_market) for _ in response]
|
68
|
+
|
69
|
+
# Filter by start and end datetime
|
70
|
+
if start:
|
71
|
+
ohlcv = [data for data in ohlcv if data.datetime.astimezone(timezone.utc) >= start.astimezone(timezone.utc)]
|
72
|
+
if end:
|
73
|
+
ohlcv = [data for data in ohlcv if data.datetime.astimezone(timezone.utc) <= end.astimezone(timezone.utc)]
|
74
|
+
|
61
75
|
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
62
76
|
|
63
77
|
security_name = symbol
|
@@ -166,9 +180,19 @@ class UpbitParser(BaseParser):
|
|
166
180
|
|
167
181
|
return ask_data, bid_data
|
168
182
|
|
169
|
-
def parse_balance(
|
170
|
-
|
171
|
-
|
183
|
+
def parse_balance(
|
184
|
+
self, response: List[Dict], base_market: str = "KRW", excluded_symbols: Optional[list[str]] = None
|
185
|
+
) -> BalanceInfo:
|
186
|
+
# 1. Filter out entries where 'currency' is not the base_market
|
187
|
+
# 2. Ensure 'unit_currency' is the base_market
|
188
|
+
# 3. Exclude entries where 'currency' is in excluded_symbols
|
189
|
+
filtered_data = [
|
190
|
+
data
|
191
|
+
for data in response
|
192
|
+
if data["currency"] != base_market
|
193
|
+
and data["unit_currency"] == base_market
|
194
|
+
and (excluded_symbols is None or data["currency"] not in excluded_symbols)
|
195
|
+
]
|
172
196
|
|
173
197
|
# Initialize balance list
|
174
198
|
balances = [self._parse_balance(data, base_market) for data in filtered_data]
|
@@ -202,8 +226,11 @@ class UpbitParser(BaseParser):
|
|
202
226
|
)
|
203
227
|
|
204
228
|
def parse_cash(self, response: List[Dict], base_market: str = "KRW") -> CashInfo:
|
205
|
-
#
|
206
|
-
|
229
|
+
# 1. Filter entries where 'currency' is equal to 'base_market'
|
230
|
+
# 2. Ensure 'unit_currency' is also equal to 'base_market'
|
231
|
+
filtered_data = [
|
232
|
+
data for data in response if data["currency"] == base_market and data["unit_currency"] == base_market
|
233
|
+
]
|
207
234
|
|
208
235
|
# 필터링된 데이터가 없으면 기본값으로 CashInfo 반환
|
209
236
|
if not filtered_data:
|
@@ -249,8 +276,21 @@ class UpbitParser(BaseParser):
|
|
249
276
|
market_ask_fee=safer.safe_number(response, "maker_ask_fee"),
|
250
277
|
)
|
251
278
|
|
252
|
-
def parse_closed_order_history(
|
279
|
+
def parse_closed_order_history(
|
280
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
281
|
+
) -> ClosedOrderHistory:
|
253
282
|
orders = [self._parse_closed_order_info(order, base_market) for order in response]
|
283
|
+
|
284
|
+
# Filter by start and end datetime
|
285
|
+
if start:
|
286
|
+
orders = [
|
287
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
288
|
+
]
|
289
|
+
if end:
|
290
|
+
orders = [
|
291
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
292
|
+
]
|
293
|
+
|
254
294
|
return ClosedOrderHistory(history=orders)
|
255
295
|
|
256
296
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -258,16 +298,30 @@ class UpbitParser(BaseParser):
|
|
258
298
|
uuid=safer.safe_string(order, "uuid"),
|
259
299
|
type=safer.safe_string(order, "side"),
|
260
300
|
symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
|
261
|
-
price=safer.safe_number(order, "
|
301
|
+
price=safer.safe_number(order, "executed_funds") / safer.safe_number(order, "volume"),
|
262
302
|
qty=safer.safe_number(order, "volume"),
|
263
|
-
amount=safer.safe_number(order, "
|
303
|
+
amount=safer.safe_number(order, "executed_funds"),
|
304
|
+
tax=0,
|
264
305
|
fee=safer.safe_number(order, "paid_fee"), # Adjusted to 'paid_fee' to match provided data
|
265
306
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
266
307
|
order_type=safer.safe_string(order, "ord_type"),
|
267
308
|
)
|
268
309
|
|
269
|
-
def parse_open_order_history(
|
310
|
+
def parse_open_order_history(
|
311
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
312
|
+
) -> OpenedOrderHistory:
|
270
313
|
orders = [self._parse_open_order_info(order, base_market) for order in response]
|
314
|
+
|
315
|
+
# Filter by start and end datetime
|
316
|
+
if start:
|
317
|
+
orders = [
|
318
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
319
|
+
]
|
320
|
+
if end:
|
321
|
+
orders = [
|
322
|
+
order for order in orders if order.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
323
|
+
]
|
324
|
+
|
271
325
|
return OpenedOrderHistory(history=orders)
|
272
326
|
|
273
327
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
@@ -275,20 +329,55 @@ class UpbitParser(BaseParser):
|
|
275
329
|
uuid=safer.safe_string(order, "uuid"),
|
276
330
|
type=safer.safe_string(order, "side"),
|
277
331
|
symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
|
278
|
-
price=safer.safe_number(order, "
|
332
|
+
price=safer.safe_number(order, "executed_funds") / safer.safe_number(order, "volume"),
|
279
333
|
qty=safer.safe_number(order, "volume"),
|
280
|
-
amount=safer.safe_number(order, "
|
334
|
+
amount=safer.safe_number(order, "executed_funds"),
|
335
|
+
tax=0,
|
281
336
|
fee=safer.safe_number(order, "reserved_fee"),
|
282
337
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
283
338
|
order_type=safer.safe_string(order, "ord_type"),
|
284
339
|
)
|
285
340
|
|
286
|
-
def parse_withdrawal_history(
|
341
|
+
def parse_withdrawal_history(
|
342
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
343
|
+
) -> WithdrawalHistory:
|
287
344
|
parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
|
345
|
+
|
346
|
+
# Filter by start and end datetime
|
347
|
+
if start:
|
348
|
+
parsed_items = [
|
349
|
+
item
|
350
|
+
for item in parsed_items
|
351
|
+
if item.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
352
|
+
]
|
353
|
+
if end:
|
354
|
+
parsed_items = [
|
355
|
+
item
|
356
|
+
for item in parsed_items
|
357
|
+
if item.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
358
|
+
]
|
359
|
+
|
288
360
|
return WithdrawalHistory(history=parsed_items)
|
289
361
|
|
290
|
-
def parse_deposit_history(
|
362
|
+
def parse_deposit_history(
|
363
|
+
self, response: List[Dict], start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
364
|
+
) -> DepositHistory:
|
291
365
|
parsed_items = [self._parse_transaction_history_item(item, base_market) for item in response]
|
366
|
+
|
367
|
+
# Filter by start and end datetime
|
368
|
+
if start:
|
369
|
+
parsed_items = [
|
370
|
+
item
|
371
|
+
for item in parsed_items
|
372
|
+
if item.created_at.astimezone(timezone.utc) >= start.astimezone(timezone.utc)
|
373
|
+
]
|
374
|
+
if end:
|
375
|
+
parsed_items = [
|
376
|
+
item
|
377
|
+
for item in parsed_items
|
378
|
+
if item.created_at.astimezone(timezone.utc) <= end.astimezone(timezone.utc)
|
379
|
+
]
|
380
|
+
|
292
381
|
return DepositHistory(history=parsed_items)
|
293
382
|
|
294
383
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
@@ -296,6 +385,7 @@ class UpbitParser(BaseParser):
|
|
296
385
|
uuid=safer.safe_string(item, "uuid"),
|
297
386
|
type=safer.safe_string(item, "type"),
|
298
387
|
amount=safer.safe_number(item, "amount"),
|
388
|
+
tax=0,
|
299
389
|
fee=safer.safe_number(item, "fee"),
|
300
390
|
currency=safer.safe_string(item, "currency"),
|
301
391
|
created_at=datetime.fromisoformat(safer.safe_string(item, "done_at")),
|