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
@@ -0,0 +1,323 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Dict, List
|
3
|
+
|
4
|
+
from ksxt.models.balance import BalanceData, BalanceInfo
|
5
|
+
from ksxt.models.cash import CashInfo
|
6
|
+
from ksxt.models.historical import HistoricalDataInfo, OHLCVData
|
7
|
+
from ksxt.models.market import HolidayHistory, HolidayInfo, MarketInfo, SecurityData, TradeFeeInfo
|
8
|
+
from ksxt.models.order import CancelOrderResponse, CreateOrderResponse, ModifyOrderResponse
|
9
|
+
from ksxt.models.orderbook import OrderBookData, OrderBookInfo
|
10
|
+
from ksxt.models.ticker import MultiSymbolTickerInfo, TickerInfo
|
11
|
+
from ksxt.models.token import TokenInfo
|
12
|
+
from ksxt.models.transaction import (
|
13
|
+
ClosedOrderHistory,
|
14
|
+
ClosedOrderInfo,
|
15
|
+
DepositHistory,
|
16
|
+
OpenedOrderHistory,
|
17
|
+
OpenedOrderInfo,
|
18
|
+
)
|
19
|
+
from ksxt.parser.parser import BaseParser
|
20
|
+
from ksxt.utils import safer, sorter, timer
|
21
|
+
|
22
|
+
|
23
|
+
class KoreaInvestParser(BaseParser):
|
24
|
+
def safe_symbol(self, base_market: str, symbol: str) -> str:
|
25
|
+
return symbol
|
26
|
+
|
27
|
+
def parse_token(self, response: dict) -> TokenInfo:
|
28
|
+
date_string = safer.safe_string(response, "access_token_token_expired")
|
29
|
+
date_format = "%Y-%m-%d %H:%M:%S"
|
30
|
+
expired_date = datetime.strptime(date_string, date_format)
|
31
|
+
|
32
|
+
return TokenInfo(
|
33
|
+
access_token=safer.safe_string(response, "access_token"),
|
34
|
+
token_type=safer.safe_string(response, "token_type"),
|
35
|
+
remain_time_second=safer.safe_number(response, "expires_in"),
|
36
|
+
expired_datetime=expired_date,
|
37
|
+
)
|
38
|
+
|
39
|
+
def parse_markets(self, response: dict, base_market: str = "KRW") -> MarketInfo:
|
40
|
+
securities = {}
|
41
|
+
for market in response:
|
42
|
+
security_data = self._parse_market(market, base_market)
|
43
|
+
securities[security_data.symbol] = security_data
|
44
|
+
|
45
|
+
return MarketInfo(market_id=base_market, securities=securities)
|
46
|
+
|
47
|
+
def _parse_market(self, market: Dict, base_market: str = "KRW") -> SecurityData:
|
48
|
+
return SecurityData(
|
49
|
+
symbol=safer.safe_string(market, "market"),
|
50
|
+
name=safer.safe_string(market, "korean_name"),
|
51
|
+
type="stock",
|
52
|
+
warning_code=safer.safe_boolean(market, " market_warning"),
|
53
|
+
)
|
54
|
+
|
55
|
+
def parse_historical_data(self, response: Dict, symbol: str, base_market: str = "KRW") -> HistoricalDataInfo:
|
56
|
+
safe_response = safer.safe_value(response, "output2")
|
57
|
+
ohlcv = [self._parse_ohlcva(_, base_market) for _ in safe_response]
|
58
|
+
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
59
|
+
|
60
|
+
security_name = symbol
|
61
|
+
|
62
|
+
result = HistoricalDataInfo(
|
63
|
+
symbol=self.safe_symbol(base_market, security_name), security_name=security_name, history=sorted_ohlcv
|
64
|
+
)
|
65
|
+
|
66
|
+
return result
|
67
|
+
|
68
|
+
def _parse_ohlcva(self, ohlcva: Dict, base_market: str = "KRW") -> OHLCVData:
|
69
|
+
fmt = "%Y%m%d"
|
70
|
+
return OHLCVData(
|
71
|
+
datetime=datetime.strptime(safer.safe_string(ohlcva, "stck_bsop_date"), fmt),
|
72
|
+
open_price=safer.safe_number(ohlcva, "stck_oprc"),
|
73
|
+
high_price=safer.safe_number(ohlcva, "stck_hgpr"),
|
74
|
+
low_price=safer.safe_number(ohlcva, "stck_lwpr"),
|
75
|
+
close_price=safer.safe_number(ohlcva, "stck_clpr"),
|
76
|
+
acml_volume=safer.safe_number(ohlcva, "acml_vol"),
|
77
|
+
acml_amount=safer.safe_number(ohlcva, "acml_tr_pbmn"),
|
78
|
+
)
|
79
|
+
|
80
|
+
def parse_historical_index_data(self, response: Dict, symbol: str, base_market: str = "KRW") -> HistoricalDataInfo:
|
81
|
+
safe_response = safer.safe_value(response, "output2")
|
82
|
+
ohlcv = [self._parse_index_ohlcva(_, base_market) for _ in safe_response]
|
83
|
+
sorted_ohlcv = sorter.sort_by(ohlcv, key="datetime")
|
84
|
+
|
85
|
+
security_name = symbol
|
86
|
+
|
87
|
+
result = HistoricalDataInfo(
|
88
|
+
symbol=self.safe_symbol(base_market, security_name), security_name=security_name, history=sorted_ohlcv
|
89
|
+
)
|
90
|
+
|
91
|
+
return result
|
92
|
+
|
93
|
+
def _parse_index_ohlcva(self, ohlcva: Dict, base_market: str = "KRW") -> OHLCVData:
|
94
|
+
fmt = "%Y%m%d"
|
95
|
+
return OHLCVData(
|
96
|
+
datetime=datetime.strptime(safer.safe_string(ohlcva, "stck_bsop_date"), fmt),
|
97
|
+
open_price=safer.safe_number(ohlcva, "bstp_nmix_oprc"),
|
98
|
+
high_price=safer.safe_number(ohlcva, "bstp_nmix_hgpr"),
|
99
|
+
low_price=safer.safe_number(ohlcva, "bstp_nmix_lwpr"),
|
100
|
+
close_price=safer.safe_number(ohlcva, "bstp_nmix_prpr"),
|
101
|
+
acml_volume=safer.safe_number(ohlcva, "acml_vol"),
|
102
|
+
acml_amount=safer.safe_number(ohlcva, "acml_tr_pbmn"),
|
103
|
+
)
|
104
|
+
|
105
|
+
def parse_ticker(self, response: List[Dict], base_market: str = "KRW") -> TickerInfo:
|
106
|
+
safe_response = safer.safe_value(response, "output")
|
107
|
+
ticker_info = self._parse_ticker(safe_response, base_market)
|
108
|
+
return ticker_info
|
109
|
+
|
110
|
+
def _parse_ticker(self, response: dict, base_market: str) -> TickerInfo:
|
111
|
+
return TickerInfo(
|
112
|
+
symbol=safer.safe_string(response, "stck_shrn_iscd"),
|
113
|
+
price=safer.safe_number(response, "stck_prpr"),
|
114
|
+
ts=datetime.now(),
|
115
|
+
)
|
116
|
+
|
117
|
+
def parse_orderbook(self, response: List[Dict], base_market: str = "KRW") -> OrderBookInfo:
|
118
|
+
ask_list = []
|
119
|
+
bid_list = []
|
120
|
+
|
121
|
+
level = 10
|
122
|
+
|
123
|
+
safe_response = safer.safe_value(response, "output1")
|
124
|
+
|
125
|
+
for index in range(1, level + 1):
|
126
|
+
ask_data, bid_data = self._parse_orderbook(safe_response, index, base_market)
|
127
|
+
ask_list.append(ask_data)
|
128
|
+
bid_list.append(bid_data)
|
129
|
+
|
130
|
+
return OrderBookInfo(
|
131
|
+
total_asks_qty=safer.safe_number(safe_response, "total_askp_rsqn"),
|
132
|
+
total_bids_qty=safer.safe_number(safe_response, "total_askp_rsqn"),
|
133
|
+
asks=ask_list,
|
134
|
+
bids=bid_list,
|
135
|
+
)
|
136
|
+
|
137
|
+
def _parse_orderbook(
|
138
|
+
self, orderbook: Dict, index: int, base_market: str = "KRW"
|
139
|
+
) -> tuple[OrderBookData, OrderBookData]:
|
140
|
+
ask_data = OrderBookData(
|
141
|
+
side="ask",
|
142
|
+
ob_num=index,
|
143
|
+
ob_price=safer.safe_number(orderbook, f"askp{index}"),
|
144
|
+
ob_qty=safer.safe_number(orderbook, f"askp_rsqn{index}"),
|
145
|
+
)
|
146
|
+
|
147
|
+
bid_data = OrderBookData(
|
148
|
+
side="bid",
|
149
|
+
ob_num=index,
|
150
|
+
ob_price=safer.safe_number(orderbook, f"bidp{index}"),
|
151
|
+
ob_qty=safer.safe_number(orderbook, f"bidp_rsqn{index}"),
|
152
|
+
)
|
153
|
+
|
154
|
+
return ask_data, bid_data
|
155
|
+
|
156
|
+
def parse_balance(self, response: List[Dict], base_market: str = "KRW") -> BalanceInfo:
|
157
|
+
safe_response = safer.safe_value(response, "output1")
|
158
|
+
|
159
|
+
# Initialize balance list
|
160
|
+
balances = [self._parse_balance(_, base_market) for _ in safe_response]
|
161
|
+
|
162
|
+
# 총 매입금액
|
163
|
+
total_amount = sum(bal.price * bal.qty for bal in balances)
|
164
|
+
total_evaluation_amount = sum(bal.evaluation_price * bal.qty for bal in balances)
|
165
|
+
total_pnl_amount = total_evaluation_amount - total_amount
|
166
|
+
total_pnl_ratio = (total_pnl_amount / total_amount * 100) if total_amount != 0 else 0
|
167
|
+
|
168
|
+
return BalanceInfo(
|
169
|
+
currency=base_market,
|
170
|
+
total_amount=total_amount,
|
171
|
+
total_evaluation_amount=total_evaluation_amount,
|
172
|
+
total_pnl_amount=total_pnl_amount,
|
173
|
+
total_pnl_ratio=total_pnl_ratio,
|
174
|
+
balances=balances,
|
175
|
+
)
|
176
|
+
|
177
|
+
def _parse_balance(self, data: Dict, base_market: str = "KRW") -> BalanceData:
|
178
|
+
return BalanceData(
|
179
|
+
symbol=safer.safe_string(data, "pdno"),
|
180
|
+
name=safer.safe_string(data, "prdt_name"),
|
181
|
+
evaluation_price=safer.safe_number(data, "evlu_amt"),
|
182
|
+
price=safer.safe_number(data, "pchs_avg_pric"),
|
183
|
+
pnl_amount=safer.safe_number(data, "evlu_pfls_amt"),
|
184
|
+
pnl_ratio=safer.safe_number(data, "evlu_pfls_rt"),
|
185
|
+
qty=safer.safe_number(data, "hldg_qty"),
|
186
|
+
free_qty=safer.safe_number(data, "ord_psbl_qty"),
|
187
|
+
used_qty=safer.safe_number(data, "hldg_qty") - safer.safe_number(data, "ord_psbl_qty"),
|
188
|
+
)
|
189
|
+
|
190
|
+
def parse_cash(self, response: List[Dict], base_market: str = "KRW") -> CashInfo:
|
191
|
+
safe_response = safer.safe_value(response, "output2")
|
192
|
+
|
193
|
+
return CashInfo(
|
194
|
+
currency=base_market,
|
195
|
+
cash=safer.safe_number(safe_response, "dnca_tot_amt"),
|
196
|
+
cash_d1=safer.safe_number(safe_response, "nxdy_excc_amt"),
|
197
|
+
cash_d2=safer.safe_number(safe_response, "prvs_rcdl_excc_amt"),
|
198
|
+
)
|
199
|
+
|
200
|
+
def parse_security(self, response: Dict, base_market: str = "KRW") -> SecurityData:
|
201
|
+
safe_response = safer.safe_value(response, "output")
|
202
|
+
|
203
|
+
return SecurityData(
|
204
|
+
symbol=safer.safe_string(safe_response, "pdno")[-6:],
|
205
|
+
name=safer.safe_string(safe_response, "prdt_name"),
|
206
|
+
type=safer.safe_string(safe_response, "mket_id_cd"),
|
207
|
+
bid_qty_unit=0, # TODO : where is information?
|
208
|
+
ask_qty_unit=0, # TODO : where is information?
|
209
|
+
bid_min_qty=0, # TODO : where is information?
|
210
|
+
ask_min_qty=0, # TODO : where is information?
|
211
|
+
bid_max_qty=0, # TODO : where is information?
|
212
|
+
ask_max_qty=0, # TODO : where is information?
|
213
|
+
bid_min_amount=0, # TODO : where is information?
|
214
|
+
ask_min_amount=0, # TODO : where is information?
|
215
|
+
bid_max_amount=0, # TODO : where is information?
|
216
|
+
ask_max_amount=0, # TODO : where is information?
|
217
|
+
# 거래정지여부 or 관리종목여부
|
218
|
+
warning_code=safer.safe_string(safe_response, "tr_stop_yn") == "Y"
|
219
|
+
or safer.safe_string(safe_response, "admn_item_yn") == "Y",
|
220
|
+
)
|
221
|
+
|
222
|
+
def parse_trade_fee(self, response: Dict, base_market: str = "KRW") -> TradeFeeInfo:
|
223
|
+
# API에서 조회되는 내역을 찾지 못해 홈페이지 안내 문을 작성함. (단위 : %)
|
224
|
+
# https://securities.koreainvestment.com/main/customer/guide/_static/TF04ae010000.jsp
|
225
|
+
|
226
|
+
# 거래수수료
|
227
|
+
trading_fee = 0.18
|
228
|
+
|
229
|
+
# 매매수수료
|
230
|
+
return TradeFeeInfo(
|
231
|
+
limit_bid_fee=0.0140527 + trading_fee,
|
232
|
+
limit_ask_fee=0.0140527 + trading_fee,
|
233
|
+
market_bid_fee=0.0140527 + trading_fee,
|
234
|
+
market_ask_fee=0.0140527 + trading_fee,
|
235
|
+
)
|
236
|
+
|
237
|
+
def parse_closed_order_history(self, response: Dict, base_market: str = "KRW") -> ClosedOrderHistory:
|
238
|
+
safe_response = safer.safe_value(response, "output1")
|
239
|
+
history = [self._parse_closed_order_info(_, base_market) for _ in safe_response]
|
240
|
+
return ClosedOrderHistory(history=history)
|
241
|
+
|
242
|
+
def _parse_closed_order_info(self, order: Dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
243
|
+
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
244
|
+
_type = "ask"
|
245
|
+
else:
|
246
|
+
_type = "bid"
|
247
|
+
|
248
|
+
return ClosedOrderInfo(
|
249
|
+
uuid=safer.safe_string(order, "odno"),
|
250
|
+
type=_type,
|
251
|
+
symbol=safer.safe_string(order, "pdno"),
|
252
|
+
price=safer.safe_number(order, "avg_prvs"),
|
253
|
+
qty=safer.safe_number(order, "tot_ccld_qty"),
|
254
|
+
amount=safer.safe_number(order, "tot_ccld_amt"),
|
255
|
+
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
256
|
+
fee=0,
|
257
|
+
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
258
|
+
order_type=safer.safe_string(order, "avg_prvs"),
|
259
|
+
)
|
260
|
+
|
261
|
+
def parse_open_order_history(self, response: Dict, base_market: str = "KRW") -> OpenedOrderHistory:
|
262
|
+
safe_response = safer.safe_value(response, "output1")
|
263
|
+
history = [self._parse_open_order_info(_, base_market) for _ in safe_response]
|
264
|
+
return OpenedOrderHistory(history=history)
|
265
|
+
|
266
|
+
def _parse_open_order_info(self, order: Dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
267
|
+
if safer.safe_string(order, "sll_buy_dvsn_cd") == "01":
|
268
|
+
_type = "ask"
|
269
|
+
else:
|
270
|
+
_type = "bid"
|
271
|
+
|
272
|
+
return OpenedOrderInfo(
|
273
|
+
uuid=safer.safe_string(order, "odno"),
|
274
|
+
type=_type,
|
275
|
+
symbol=safer.safe_string(order, "pdno"),
|
276
|
+
price=safer.safe_number(order, "avg_prvs"),
|
277
|
+
qty=safer.safe_number(order, "tot_ccld_qty"),
|
278
|
+
amount=safer.safe_number(order, "tot_ccld_amt"),
|
279
|
+
# 단일 주문 이력에는 수수료 관련 정보가 없고, 조회한 전체 목록에 대해 수수료 정보만 존재한다.
|
280
|
+
fee=0,
|
281
|
+
created_at=datetime.fromisoformat(safer.safe_string(order, "ord_dt")),
|
282
|
+
order_type=safer.safe_string(order, "avg_prvs"),
|
283
|
+
)
|
284
|
+
|
285
|
+
def parse_create_order(self, response: Dict, base_market: str = "KRW") -> CreateOrderResponse:
|
286
|
+
safe_response = safer.safe_value(response, "output")
|
287
|
+
fmt = "%Y%m%d"
|
288
|
+
|
289
|
+
order_hhmmss = datetime.strptime(safer.safe_string(safe_response, "ORD_TMD"), fmt)
|
290
|
+
order_datetime = timer.create_datetime_with_today(order_hhmmss)
|
291
|
+
|
292
|
+
return CreateOrderResponse(order_datetime=order_datetime, order_id=safer.safe_string(safe_response, "ODNO"))
|
293
|
+
|
294
|
+
def parse_cancel_order(self, response: Dict, base_market: str = "KRW") -> CancelOrderResponse:
|
295
|
+
safe_response = safer.safe_value(response, "output")
|
296
|
+
fmt = "%Y%m%d"
|
297
|
+
|
298
|
+
order_hhmmss = datetime.strptime(safer.safe_string(safe_response, "ORD_TMD"), fmt)
|
299
|
+
order_datetime = timer.create_datetime_with_today(order_hhmmss)
|
300
|
+
|
301
|
+
return CancelOrderResponse(order_datetime=order_datetime, order_id=safer.safe_string(safe_response, "ODNO"))
|
302
|
+
|
303
|
+
def parse_modify_order(self, response: Dict, base_market: str = "KRW") -> ModifyOrderResponse:
|
304
|
+
safe_response = safer.safe_value(response, "output")
|
305
|
+
fmt = "%Y%m%d"
|
306
|
+
|
307
|
+
order_hhmmss = datetime.strptime(safer.safe_string(safe_response, "ORD_TMD"), fmt)
|
308
|
+
order_datetime = timer.create_datetime_with_today(order_hhmmss)
|
309
|
+
|
310
|
+
return ModifyOrderResponse(order_datetime=order_datetime, order_id=safer.safe_string(safe_response, "ODNO"))
|
311
|
+
|
312
|
+
def parse_is_holiday(self, response: List[Dict], base_market: str = "KRW") -> HolidayHistory:
|
313
|
+
safe_response = safer.safe_value(response, "output")
|
314
|
+
history = [self._parse_is_holiday(_, base_market) for _ in safe_response]
|
315
|
+
|
316
|
+
return HolidayHistory(market=["kospi", "kosdaq"], country="KR", history=history)
|
317
|
+
|
318
|
+
def _parse_is_holiday(self, item: Dict, base_market: str = "KRW") -> HolidayInfo:
|
319
|
+
return HolidayInfo(
|
320
|
+
date=datetime.strptime(safer.safe_string(item, "bass_dt"), "%Y%m%d"),
|
321
|
+
weekend=safer.safe_string(item, "wday_dvsn_cd"),
|
322
|
+
is_holiday=not safer.safe_boolean(item, "opnd_yn"),
|
323
|
+
)
|
ksxt/parser/parser.py
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
from typing import Dict, List
|
2
|
+
import inspect
|
3
|
+
|
4
|
+
from ksxt.models.balance import BalanceData, BalanceInfo
|
5
|
+
from ksxt.models.cash import CashInfo
|
6
|
+
from ksxt.models.historical import HistoricalDataInfo, OHLCVData
|
7
|
+
from ksxt.models.market import HolidayHistory, HolidayInfo, MarketInfo, SecurityData, TradeFeeInfo
|
8
|
+
from ksxt.models.order import CancelOrderResponse, CreateOrderResponse, ModifyOrderResponse
|
9
|
+
from ksxt.models.orderbook import MultiSymbolOrderBookInfos, OrderBookData, OrderBookInfo
|
10
|
+
from ksxt.models.ticker import MultiSymbolTickerInfo, TickerInfo
|
11
|
+
from ksxt.models.transaction import (
|
12
|
+
ClosedOrderHistory,
|
13
|
+
ClosedOrderInfo,
|
14
|
+
DepositHistory,
|
15
|
+
OpenedOrderHistory,
|
16
|
+
OpenedOrderInfo,
|
17
|
+
TransactionInfo,
|
18
|
+
WithdrawalHistory,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
class BaseParser:
|
23
|
+
def _raise_not_implemented_error(self):
|
24
|
+
caller = inspect.stack()[1].function
|
25
|
+
raise NotImplementedError(f"{self.__class__.__name__} called {caller}")
|
26
|
+
|
27
|
+
def parse_markets(self, response: List[Dict], base_market: str = "KRW") -> MarketInfo:
|
28
|
+
self._raise_not_implemented_error()
|
29
|
+
|
30
|
+
def _parse_market(self, market: Dict) -> SecurityData:
|
31
|
+
self._raise_not_implemented_error()
|
32
|
+
|
33
|
+
def parse_historical_data(self, response: dict, symbol: str, base_market: str = "KRW") -> HistoricalDataInfo:
|
34
|
+
self._raise_not_implemented_error()
|
35
|
+
|
36
|
+
def _parse_ohlcva(self, ohlcva: dict, base_market: str = "KRW") -> OHLCVData:
|
37
|
+
self._raise_not_implemented_error()
|
38
|
+
|
39
|
+
def parse_historical_index_data(self, response: dict, symbol: str, base_market: str = "KRW") -> HistoricalDataInfo:
|
40
|
+
self._raise_not_implemented_error()
|
41
|
+
|
42
|
+
def _parse_index_ohlcva(self, ohlcva: dict, base_market: str = "KRW") -> OHLCVData:
|
43
|
+
self._raise_not_implemented_error()
|
44
|
+
|
45
|
+
def parse_ticker(self, response: List[Dict], base_market: str = "KRW") -> TickerInfo:
|
46
|
+
self._raise_not_implemented_error()
|
47
|
+
|
48
|
+
def parse_tickers(self, response: List[Dict], base_market: str = "KRW") -> MultiSymbolTickerInfo:
|
49
|
+
self._raise_not_implemented_error()
|
50
|
+
|
51
|
+
def _parse_ticker(self, response: dict, base_market: str) -> TickerInfo:
|
52
|
+
self._raise_not_implemented_error()
|
53
|
+
|
54
|
+
def parse_orderbook(self, response: List[Dict], base_market: str = "KRW") -> OrderBookInfo:
|
55
|
+
self._raise_not_implemented_error()
|
56
|
+
|
57
|
+
def parse_orderbooks(self, response: dict, base_market: str) -> MultiSymbolOrderBookInfos:
|
58
|
+
self._raise_not_implemented_error()
|
59
|
+
|
60
|
+
def _parse_orderbook(
|
61
|
+
self, orderbook: dict, index: int, base_market: str = "KRW"
|
62
|
+
) -> tuple[OrderBookData, OrderBookData]:
|
63
|
+
self._raise_not_implemented_error()
|
64
|
+
|
65
|
+
def parse_balance(self, response: List[Dict], base_market: str = "KRW") -> BalanceInfo:
|
66
|
+
self._raise_not_implemented_error()
|
67
|
+
|
68
|
+
def _parse_balance(self, data: Dict, base_market: str = "KRW") -> BalanceData:
|
69
|
+
self._raise_not_implemented_error()
|
70
|
+
|
71
|
+
def parse_cash(self, response: List[Dict], base_market: str = "KRW") -> CashInfo:
|
72
|
+
self._raise_not_implemented_error()
|
73
|
+
|
74
|
+
def parse_security(self, response: dict, base_market: str = "KRW") -> SecurityData:
|
75
|
+
self._raise_not_implemented_error()
|
76
|
+
|
77
|
+
def parse_trade_fee(self, response: dict, base_market: str = "KRW") -> TradeFeeInfo:
|
78
|
+
self._raise_not_implemented_error()
|
79
|
+
|
80
|
+
def parse_open_order_history(self, response: dict, base_market: str = "KRW") -> OpenedOrderHistory:
|
81
|
+
self._raise_not_implemented_error()
|
82
|
+
|
83
|
+
def _parse_open_order_info(self, order: dict, base_market: str = "KRW") -> OpenedOrderInfo:
|
84
|
+
self._raise_not_implemented_error()
|
85
|
+
|
86
|
+
def parse_closed_order_history(self, response: dict, base_market: str = "KRW") -> ClosedOrderHistory:
|
87
|
+
self._raise_not_implemented_error()
|
88
|
+
|
89
|
+
def _parse_closed_order_info(self, order: dict, base_market: str = "KRW") -> ClosedOrderInfo:
|
90
|
+
self._raise_not_implemented_error()
|
91
|
+
|
92
|
+
def parse_modify_order(self, response: dict, base_market: str = "KRW") -> ModifyOrderResponse:
|
93
|
+
self._raise_not_implemented_error()
|
94
|
+
|
95
|
+
def parse_cancel_order(self, response: dict, base_market: str = "KRW") -> CancelOrderResponse:
|
96
|
+
self._raise_not_implemented_error()
|
97
|
+
|
98
|
+
def parse_create_order(self, response: dict, base_market: str = "KRW") -> CreateOrderResponse:
|
99
|
+
self._raise_not_implemented_error()
|
100
|
+
|
101
|
+
def parse_withdrawal_history(self, response: List[Dict], base_market: str = "KRW") -> WithdrawalHistory:
|
102
|
+
self._raise_not_implemented_error()
|
103
|
+
|
104
|
+
def parse_deposit_history(self, response: List[Dict], base_market: str = "KRW") -> DepositHistory:
|
105
|
+
self._raise_not_implemented_error()
|
106
|
+
|
107
|
+
def _parse_transaction_history_item(self, item: Dict, base_market: str = "KRW") -> TransactionInfo:
|
108
|
+
self._raise_not_implemented_error()
|
109
|
+
|
110
|
+
def parse_is_holiday(self, response: List[Dict], base_market: str = "KRW") -> HolidayHistory:
|
111
|
+
self._raise_not_implemented_error()
|
112
|
+
|
113
|
+
def _parse_is_holiday(self, item: Dict, base_market: str = "KRW") -> HolidayInfo:
|
114
|
+
self._raise_not_implemented_error()
|