ksxt 1.0.4__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__/__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/__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/__pycache__/bithumb.cpython-312.pyc +0 -0
- ksxt/api/auto/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/api/auto/__pycache__/upbit.cpython-312.pyc +0 -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/__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 +17 -17
- ksxt/async_/bithumb.py +37 -19
- ksxt/async_/koreainvest.py +74 -6
- ksxt/async_/upbit.py +52 -20
- 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__/rate_limiter.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/exchange.py +31 -23
- ksxt/base/rest_exchange.py +26 -28
- ksxt/bithumb.py +29 -12
- ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/config/token.toml +6 -6
- ksxt/koreainvest.py +24 -6
- 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/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/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/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/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 +83 -6
- ksxt/parser/koreainvest.py +56 -8
- ksxt/parser/parser.py +21 -5
- ksxt/parser/upbit.py +87 -10
- ksxt/upbit.py +42 -16
- 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-1.0.4.dist-info → ksxt-1.0.5.dist-info}/METADATA +1 -1
- ksxt-1.0.5.dist-info/RECORD +123 -0
- {ksxt-1.0.4.dist-info → ksxt-1.0.5.dist-info}/WHEEL +1 -1
- ksxt-1.0.4.dist-info/RECORD +0 -120
- {ksxt-1.0.4.dist-info → ksxt-1.0.5.dist-info}/LICENSE.txt +0 -0
- {ksxt-1.0.4.dist-info → ksxt-1.0.5.dist-info}/top_level.txt +0 -0
ksxt/parser/bithumb.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from datetime import datetime
|
1
|
+
from datetime import datetime, timezone
|
2
2
|
from operator import attrgetter
|
3
3
|
from typing import Dict, List, Optional
|
4
4
|
|
@@ -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
|
@@ -256,8 +270,21 @@ class BithumbParser(BaseParser):
|
|
256
270
|
market_ask_fee=safer.safe_number(response, "maker_ask_fee"),
|
257
271
|
)
|
258
272
|
|
259
|
-
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:
|
260
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
|
+
|
261
288
|
return OpenedOrderHistory(history=orders)
|
262
289
|
|
263
290
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
@@ -268,13 +295,27 @@ class BithumbParser(BaseParser):
|
|
268
295
|
price=safer.safe_number(order, "price"),
|
269
296
|
qty=safer.safe_number(order, "volume"),
|
270
297
|
amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
|
298
|
+
tax=0,
|
271
299
|
fee=safer.safe_number(order, "reserved_fee"),
|
272
300
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
273
301
|
order_type=safer.safe_string(order, "ord_type"),
|
274
302
|
)
|
275
303
|
|
276
|
-
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:
|
277
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
|
+
|
278
319
|
return ClosedOrderHistory(history=orders)
|
279
320
|
|
280
321
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -285,6 +326,7 @@ class BithumbParser(BaseParser):
|
|
285
326
|
price=safer.safe_number(order, "price"),
|
286
327
|
qty=safer.safe_number(order, "volume"),
|
287
328
|
amount=safer.safe_number(order, "price") * safer.safe_number(order, "volume"),
|
329
|
+
tax=0,
|
288
330
|
fee=safer.safe_number(order, "reserved_fee"),
|
289
331
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
290
332
|
order_type=safer.safe_string(order, "ord_type"),
|
@@ -296,12 +338,46 @@ class BithumbParser(BaseParser):
|
|
296
338
|
def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
|
297
339
|
return CreateOrderResponse(order_datetime=datetime.now(), order_id=safer.safe_string(response, "uuid"))
|
298
340
|
|
299
|
-
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:
|
300
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
|
+
|
301
360
|
return WithdrawalHistory(history=parsed_items)
|
302
361
|
|
303
|
-
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:
|
304
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
|
+
|
305
381
|
return DepositHistory(history=parsed_items)
|
306
382
|
|
307
383
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
@@ -309,6 +385,7 @@ class BithumbParser(BaseParser):
|
|
309
385
|
uuid=safer.safe_string(item, "uuid"),
|
310
386
|
type=safer.safe_string(item, "type"),
|
311
387
|
amount=safer.safe_number(item, "amount"),
|
388
|
+
tax=0,
|
312
389
|
fee=safer.safe_number(item, "fee"),
|
313
390
|
currency=safer.safe_string(item, "currency"),
|
314
391
|
created_at=datetime.fromisoformat(safer.safe_string(item, "created_at")),
|
ksxt/parser/koreainvest.py
CHANGED
@@ -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
|
@@ -242,10 +270,19 @@ class KoreaInvestParser(BaseParser):
|
|
242
270
|
market_ask_fee=0.0140527 + trading_fee,
|
243
271
|
)
|
244
272
|
|
245
|
-
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:
|
246
276
|
safe_response = safer.safe_value(response, "output1")
|
247
|
-
|
248
|
-
|
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)
|
249
286
|
|
250
287
|
def _parse_closed_order_info(self, order: Dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
251
288
|
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
@@ -260,16 +297,26 @@ class KoreaInvestParser(BaseParser):
|
|
260
297
|
price=safer.safe_number(order, "avg_prvs"),
|
261
298
|
qty=safer.safe_number(order, "tot_ccld_qty"),
|
262
299
|
amount=safer.safe_number(order, "tot_ccld_amt"),
|
300
|
+
tax=0,
|
263
301
|
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
264
302
|
fee=0,
|
265
303
|
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
266
304
|
order_type=safer.safe_string(order, "avg_prvs"),
|
267
305
|
)
|
268
306
|
|
269
|
-
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:
|
270
310
|
safe_response = safer.safe_value(response, "output1")
|
271
|
-
|
272
|
-
|
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)
|
273
320
|
|
274
321
|
def _parse_open_order_info(self, order: Dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
275
322
|
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
@@ -284,6 +331,7 @@ class KoreaInvestParser(BaseParser):
|
|
284
331
|
price=safer.safe_number(order, "avg_prvs"),
|
285
332
|
qty=safer.safe_number(order, "tot_ccld_qty"),
|
286
333
|
amount=safer.safe_number(order, "tot_ccld_amt"),
|
334
|
+
tax=0,
|
287
335
|
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
288
336
|
fee=0,
|
289
337
|
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
ksxt/parser/parser.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from datetime import datetime
|
1
2
|
from typing import Dict, List, Optional
|
2
3
|
import inspect
|
3
4
|
|
@@ -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:
|
@@ -79,13 +87,17 @@ class BaseParser:
|
|
79
87
|
def parse_trade_fee(self, response: dict, base_market: str = "KRW") -> TradeFeeInfo:
|
80
88
|
self._raise_not_implemented_error()
|
81
89
|
|
82
|
-
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:
|
83
93
|
self._raise_not_implemented_error()
|
84
94
|
|
85
95
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
86
96
|
self._raise_not_implemented_error()
|
87
97
|
|
88
|
-
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:
|
89
101
|
self._raise_not_implemented_error()
|
90
102
|
|
91
103
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -100,10 +112,14 @@ class BaseParser:
|
|
100
112
|
def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
|
101
113
|
self._raise_not_implemented_error()
|
102
114
|
|
103
|
-
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:
|
104
118
|
self._raise_not_implemented_error()
|
105
119
|
|
106
|
-
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:
|
107
123
|
self._raise_not_implemented_error()
|
108
124
|
|
109
125
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
ksxt/parser/upbit.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from datetime import datetime
|
1
|
+
from datetime import datetime, timezone
|
2
2
|
from operator import attrgetter
|
3
3
|
from typing import Dict, List, Optional
|
4
4
|
|
@@ -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
|
@@ -262,8 +276,21 @@ class UpbitParser(BaseParser):
|
|
262
276
|
market_ask_fee=safer.safe_number(response, "maker_ask_fee"),
|
263
277
|
)
|
264
278
|
|
265
|
-
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:
|
266
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
|
+
|
267
294
|
return ClosedOrderHistory(history=orders)
|
268
295
|
|
269
296
|
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
@@ -271,16 +298,30 @@ class UpbitParser(BaseParser):
|
|
271
298
|
uuid=safer.safe_string(order, "uuid"),
|
272
299
|
type=safer.safe_string(order, "side"),
|
273
300
|
symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
|
274
|
-
price=safer.safe_number(order, "
|
301
|
+
price=safer.safe_number(order, "executed_funds") / safer.safe_number(order, "volume"),
|
275
302
|
qty=safer.safe_number(order, "volume"),
|
276
|
-
amount=safer.safe_number(order, "
|
303
|
+
amount=safer.safe_number(order, "executed_funds"),
|
304
|
+
tax=0,
|
277
305
|
fee=safer.safe_number(order, "paid_fee"), # Adjusted to 'paid_fee' to match provided data
|
278
306
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
279
307
|
order_type=safer.safe_string(order, "ord_type"),
|
280
308
|
)
|
281
309
|
|
282
|
-
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:
|
283
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
|
+
|
284
325
|
return OpenedOrderHistory(history=orders)
|
285
326
|
|
286
327
|
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
@@ -288,20 +329,55 @@ class UpbitParser(BaseParser):
|
|
288
329
|
uuid=safer.safe_string(order, "uuid"),
|
289
330
|
type=safer.safe_string(order, "side"),
|
290
331
|
symbol=self.safe_symbol(base_market, safer.safe_string(order, "market")),
|
291
|
-
price=safer.safe_number(order, "
|
332
|
+
price=safer.safe_number(order, "executed_funds") / safer.safe_number(order, "volume"),
|
292
333
|
qty=safer.safe_number(order, "volume"),
|
293
|
-
amount=safer.safe_number(order, "
|
334
|
+
amount=safer.safe_number(order, "executed_funds"),
|
335
|
+
tax=0,
|
294
336
|
fee=safer.safe_number(order, "reserved_fee"),
|
295
337
|
created_at=datetime.fromisoformat(safer.safe_string(order, "created_at")),
|
296
338
|
order_type=safer.safe_string(order, "ord_type"),
|
297
339
|
)
|
298
340
|
|
299
|
-
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:
|
300
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
|
+
|
301
360
|
return WithdrawalHistory(history=parsed_items)
|
302
361
|
|
303
|
-
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:
|
304
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
|
+
|
305
381
|
return DepositHistory(history=parsed_items)
|
306
382
|
|
307
383
|
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
@@ -309,6 +385,7 @@ class UpbitParser(BaseParser):
|
|
309
385
|
uuid=safer.safe_string(item, "uuid"),
|
310
386
|
type=safer.safe_string(item, "type"),
|
311
387
|
amount=safer.safe_number(item, "amount"),
|
388
|
+
tax=0,
|
312
389
|
fee=safer.safe_number(item, "fee"),
|
313
390
|
currency=safer.safe_string(item, "currency"),
|
314
391
|
created_at=datetime.fromisoformat(safer.safe_string(item, "done_at")),
|
ksxt/upbit.py
CHANGED
@@ -2,7 +2,7 @@ import hashlib
|
|
2
2
|
import json
|
3
3
|
import time
|
4
4
|
import uuid
|
5
|
-
from datetime import datetime
|
5
|
+
from datetime import datetime, timezone
|
6
6
|
from typing import Any, Dict, List, Literal, Optional
|
7
7
|
from urllib.parse import urlencode
|
8
8
|
|
@@ -123,10 +123,19 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
123
123
|
return ksxt.models.KsxtMarketResponse(header=common_header, response=common_response, info=parsed_info)
|
124
124
|
|
125
125
|
def fetch_historical_data(
|
126
|
-
self,
|
126
|
+
self,
|
127
|
+
symbol: str,
|
128
|
+
time_frame: str,
|
129
|
+
start: datetime | None = None,
|
130
|
+
end: datetime | None = None,
|
131
|
+
base_market: str = "KRW",
|
127
132
|
) -> ksxt.models.KsxtHistoricalDataResponse:
|
128
133
|
params = {"market": self.safe_symbol(base_market, symbol), "count": 200}
|
129
134
|
|
135
|
+
if end:
|
136
|
+
end_utc = end.astimezone(timezone.utc)
|
137
|
+
params.update({"to": end_utc.strftime("%Y-%m-%d %H:%M:%S")})
|
138
|
+
|
130
139
|
# TODO : time_frame 을 어떻게 고정시킬까? 우리는 분봉, 일봉, 주봉, 월봉 만 지원한다고 가정하면?
|
131
140
|
if time_frame.endswith("m"):
|
132
141
|
# TODO : parse number
|
@@ -152,9 +161,13 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
152
161
|
if common_response.success != "0":
|
153
162
|
return ksxt.models.KsxtHistoricalDataResponse(header=common_header, response=common_response, info=None)
|
154
163
|
|
155
|
-
|
164
|
+
parsed_response = self.parser.parse_historical_data(
|
165
|
+
response=response, symbol=symbol, start=start, end=end, base_market=base_market
|
166
|
+
)
|
156
167
|
|
157
|
-
return ksxt.models.KsxtHistoricalDataResponse(
|
168
|
+
return ksxt.models.KsxtHistoricalDataResponse(
|
169
|
+
header=common_header, response=common_response, info=parsed_response
|
170
|
+
)
|
158
171
|
|
159
172
|
def fetch_ticker(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTickerResponse:
|
160
173
|
params = {"markets": self.safe_symbol(base_market, symbol)} # 다중 조회 시, 콤마로 구분 ex. 'KRW-BTC, BTC-ETH'
|
@@ -335,8 +348,8 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
335
348
|
self,
|
336
349
|
acc_num: str,
|
337
350
|
symbol: Optional[str] = "",
|
338
|
-
start:
|
339
|
-
end:
|
351
|
+
start: datetime | None = None,
|
352
|
+
end: datetime | None = None,
|
340
353
|
base_market: str = "KRW",
|
341
354
|
) -> ksxt.models.KsxtClosedOrderResponse:
|
342
355
|
params = {"state": "done"}
|
@@ -352,16 +365,18 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
352
365
|
if common_response.success != "0":
|
353
366
|
return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=None)
|
354
367
|
|
355
|
-
|
356
|
-
|
368
|
+
# 데이터 파싱
|
369
|
+
parsed_info = self.parser.parse_closed_order_history(
|
370
|
+
response=response, start=start, end=end, base_market=base_market
|
371
|
+
)
|
357
372
|
return ksxt.models.KsxtClosedOrderResponse(header=common_header, response=common_response, info=parsed_info)
|
358
373
|
|
359
374
|
def fetch_open_order(
|
360
375
|
self,
|
361
376
|
acc_num: str,
|
362
|
-
symbol: str
|
363
|
-
start:
|
364
|
-
end:
|
377
|
+
symbol: Optional[str] = "",
|
378
|
+
start: datetime | None = None,
|
379
|
+
end: datetime | None = None,
|
365
380
|
base_market: str = "KRW",
|
366
381
|
) -> ksxt.models.KsxtOpenOrderResponse:
|
367
382
|
params = {"state": "wait"}
|
@@ -377,12 +392,15 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
377
392
|
if common_response.success != "0":
|
378
393
|
return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=None)
|
379
394
|
|
380
|
-
|
395
|
+
# 데이터 파싱
|
396
|
+
parsed_info = self.parser.parse_open_order_history(
|
397
|
+
response=response, start=start, end=end, base_market=base_market
|
398
|
+
)
|
381
399
|
|
382
400
|
return ksxt.models.KsxtOpenOrderResponse(header=common_header, response=common_response, info=parsed_info)
|
383
401
|
|
384
402
|
def fetch_withdrawal_history(
|
385
|
-
self, acc_num: str, base_market: str = "KRW"
|
403
|
+
self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
386
404
|
) -> ksxt.models.KsxtWithdrawalHistoryResponse:
|
387
405
|
params = {"currency": base_market, "state": "DONE"}
|
388
406
|
|
@@ -394,13 +412,18 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
394
412
|
if common_response.success != "0":
|
395
413
|
return ksxt.models.KsxtWithdrawalHistoryResponse(header=common_header, response=common_response, info=None)
|
396
414
|
|
397
|
-
|
415
|
+
# 데이터 파싱
|
416
|
+
parsed_info = self.parser.parse_withdrawal_history(
|
417
|
+
response=response, start=start, end=end, base_market=base_market
|
418
|
+
)
|
398
419
|
|
399
420
|
return ksxt.models.KsxtWithdrawalHistoryResponse(
|
400
421
|
header=common_header, response=common_response, info=parsed_info
|
401
422
|
)
|
402
423
|
|
403
|
-
def fetch_deposit_history(
|
424
|
+
def fetch_deposit_history(
|
425
|
+
self, acc_num: str, start: datetime | None = None, end: datetime | None = None, base_market: str = "KRW"
|
426
|
+
) -> ksxt.models.KsxtDepositHistoryResponse:
|
404
427
|
params = {"currency": base_market, "state": "ACCEPTED"}
|
405
428
|
|
406
429
|
common_header = self.create_common_header(request_params=params)
|
@@ -411,7 +434,10 @@ class Upbit(RestExchange, ImplicitAPI):
|
|
411
434
|
if common_response.success != "0":
|
412
435
|
return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=None)
|
413
436
|
|
414
|
-
|
437
|
+
# 데이터 파싱
|
438
|
+
parsed_info = self.parser.parse_deposit_history(
|
439
|
+
response=response, start=start, end=end, base_market=base_market
|
440
|
+
)
|
415
441
|
|
416
442
|
return ksxt.models.KsxtDepositHistoryResponse(header=common_header, response=common_response, info=parsed_info)
|
417
443
|
|
Binary file
|
Binary file
|
Binary file
|