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.
Files changed (141) hide show
  1. ksxt/__init__.py +3 -1
  2. ksxt/__pycache__/__init__.cpython-312.pyc +0 -0
  3. ksxt/__pycache__/bithumb.cpython-312.pyc +0 -0
  4. ksxt/__pycache__/koreainvest.cpython-312.pyc +0 -0
  5. ksxt/__pycache__/upbit.cpython-312.pyc +0 -0
  6. ksxt/api/__init__.py +26 -0
  7. ksxt/api/__pycache__/__init__.cpython-312.pyc +0 -0
  8. ksxt/api/__pycache__/bithumb.cpython-312.pyc +0 -0
  9. ksxt/api/__pycache__/koreainvest.cpython-312.pyc +0 -0
  10. ksxt/api/__pycache__/upbit.cpython-312.pyc +0 -0
  11. ksxt/api/auto/api_generator.py +54 -0
  12. ksxt/api/auto/bithumb.py +35 -0
  13. ksxt/api/auto/koreainvest.py +49 -0
  14. ksxt/api/auto/upbit.py +39 -0
  15. ksxt/api/bithumb.py +42 -0
  16. ksxt/api/koreainvest.py +40 -0
  17. ksxt/api/upbit.py +54 -0
  18. ksxt/async_/__init__.py +4 -0
  19. ksxt/async_/__pycache__/__init__.cpython-312.pyc +0 -0
  20. ksxt/async_/__pycache__/bithumb.cpython-312.pyc +0 -0
  21. ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
  22. ksxt/async_/__pycache__/upbit.cpython-312.pyc +0 -0
  23. ksxt/async_/base/__init__.py +0 -0
  24. ksxt/async_/base/__pycache__/__init__.cpython-312.pyc +0 -0
  25. ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
  26. ksxt/async_/base/__pycache__/throttler.cpython-312.pyc +0 -0
  27. ksxt/async_/base/async_exchange.py +232 -0
  28. ksxt/async_/base/throttler.py +63 -0
  29. ksxt/async_/bithumb.py +455 -0
  30. ksxt/async_/koreainvest.py +849 -0
  31. ksxt/async_/upbit.py +488 -0
  32. ksxt/base/__pycache__/__init__.cpython-312.pyc +0 -0
  33. ksxt/base/__pycache__/errors.cpython-312.pyc +0 -0
  34. ksxt/base/__pycache__/exchange.cpython-312.pyc +0 -0
  35. ksxt/base/__pycache__/rest_exchange.cpython-312.pyc +0 -0
  36. ksxt/base/__pycache__/types.cpython-312.pyc +0 -0
  37. ksxt/base/com_exchange.py +2 -2
  38. ksxt/base/errors.py +10 -0
  39. ksxt/base/exchange.py +188 -497
  40. ksxt/base/rest_exchange.py +297 -113
  41. ksxt/base/types.py +1 -36
  42. ksxt/bithumb.py +504 -0
  43. ksxt/config/__init__.py +2 -1
  44. ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
  45. ksxt/config/bithumb.toml +380 -0
  46. ksxt/config/koreainvest.toml +312 -0
  47. ksxt/config/token.toml +7 -0
  48. ksxt/config/upbit.toml +428 -0
  49. ksxt/koreainvest.py +409 -1055
  50. ksxt/market/__pycache__/base.cpython-312.pyc +0 -0
  51. ksxt/market/__pycache__/db.cpython-312.pyc +0 -0
  52. ksxt/market/__pycache__/logging.cpython-312.pyc +0 -0
  53. ksxt/market/__pycache__/manager.cpython-312.pyc +0 -0
  54. ksxt/market/__pycache__/markets.cpython-312.pyc +0 -0
  55. ksxt/market/base.py +50 -50
  56. ksxt/market/db.py +5 -4
  57. ksxt/market/krx/__pycache__/kosdaq.cpython-312.pyc +0 -0
  58. ksxt/market/krx/__pycache__/kospi.cpython-312.pyc +0 -0
  59. ksxt/market/krx/__pycache__/stock.cpython-312.pyc +0 -0
  60. ksxt/market/krx/kosdaq.py +150 -147
  61. ksxt/market/krx/kospi.py +179 -175
  62. ksxt/market/krx/stock.py +136 -134
  63. ksxt/market/logging.py +4 -4
  64. ksxt/market/manager.py +10 -12
  65. ksxt/market/markets.py +1 -1
  66. ksxt/market/us/__pycache__/amex.cpython-312.pyc +0 -0
  67. ksxt/market/us/__pycache__/nasdaq.cpython-312.pyc +0 -0
  68. ksxt/market/us/__pycache__/nyse.cpython-312.pyc +0 -0
  69. ksxt/market/us/__pycache__/stock.cpython-312.pyc +0 -0
  70. ksxt/market/us/amex.py +31 -31
  71. ksxt/market/us/nasdaq.py +31 -31
  72. ksxt/market/us/nyse.py +31 -31
  73. ksxt/market/us/stock.py +20 -28
  74. ksxt/models/__init__.py +16 -0
  75. ksxt/models/__pycache__/__init__.cpython-312.pyc +0 -0
  76. ksxt/models/__pycache__/balance.cpython-312.pyc +0 -0
  77. ksxt/models/__pycache__/cash.cpython-312.pyc +0 -0
  78. ksxt/models/__pycache__/common.cpython-312.pyc +0 -0
  79. ksxt/models/__pycache__/error.cpython-312.pyc +0 -0
  80. ksxt/models/__pycache__/historical.cpython-312.pyc +0 -0
  81. ksxt/models/__pycache__/market.cpython-312.pyc +0 -0
  82. ksxt/models/__pycache__/order.cpython-312.pyc +0 -0
  83. ksxt/models/__pycache__/orderbook.cpython-312.pyc +0 -0
  84. ksxt/models/__pycache__/ticker.cpython-312.pyc +0 -0
  85. ksxt/models/__pycache__/token.cpython-312.pyc +0 -0
  86. ksxt/models/__pycache__/transaction.cpython-312.pyc +0 -0
  87. ksxt/models/balance.py +30 -0
  88. ksxt/models/cash.py +15 -0
  89. ksxt/models/common.py +31 -0
  90. ksxt/models/error.py +13 -0
  91. ksxt/models/historical.py +26 -0
  92. ksxt/models/market.py +81 -0
  93. ksxt/models/order.py +42 -0
  94. ksxt/models/orderbook.py +32 -0
  95. ksxt/models/ticker.py +25 -0
  96. ksxt/models/token.py +14 -0
  97. ksxt/models/transaction.py +79 -0
  98. ksxt/parser/__pycache__/bithumb.cpython-312.pyc +0 -0
  99. ksxt/parser/__pycache__/koreainvest.cpython-312.pyc +0 -0
  100. ksxt/parser/__pycache__/parser.cpython-312.pyc +0 -0
  101. ksxt/parser/__pycache__/upbit.cpython-312.pyc +0 -0
  102. ksxt/parser/bithumb.py +300 -0
  103. ksxt/parser/koreainvest.py +323 -0
  104. ksxt/parser/parser.py +114 -0
  105. ksxt/parser/upbit.py +308 -0
  106. ksxt/upbit.py +499 -0
  107. ksxt/utils/__pycache__/safer.cpython-312.pyc +0 -0
  108. ksxt/utils/__pycache__/sorter.cpython-312.pyc +0 -0
  109. ksxt/utils/__pycache__/timer.cpython-312.pyc +0 -0
  110. ksxt/utils/safer.py +48 -0
  111. ksxt/utils/sorter.py +8 -0
  112. ksxt/utils/timer.py +47 -0
  113. {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/METADATA +11 -1
  114. ksxt-0.0.10.dist-info/RECORD +119 -0
  115. {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/WHEEL +1 -1
  116. ksxt/__pycache__/__init__.cpython-39.pyc +0 -0
  117. ksxt/__pycache__/koreainvest.cpython-39.pyc +0 -0
  118. ksxt/base/__pycache__/__init__.cpython-39.pyc +0 -0
  119. ksxt/base/__pycache__/exchange.cpython-39.pyc +0 -0
  120. ksxt/base/__pycache__/rest_exchange.cpython-39.pyc +0 -0
  121. ksxt/base/__pycache__/restexchange.cpython-39.pyc +0 -0
  122. ksxt/base/__pycache__/types.cpython-39.pyc +0 -0
  123. ksxt/base/api_response.py +0 -68
  124. ksxt/config/__pycache__/__init__.cpython-39.pyc +0 -0
  125. ksxt/config/tr_app.json +0 -381
  126. ksxt/config/tr_dev.json +0 -446
  127. ksxt/market/__pycache__/base.cpython-39.pyc +0 -0
  128. ksxt/market/__pycache__/db.cpython-39.pyc +0 -0
  129. ksxt/market/__pycache__/logging.cpython-39.pyc +0 -0
  130. ksxt/market/__pycache__/manager.cpython-39.pyc +0 -0
  131. ksxt/market/__pycache__/markets.cpython-39.pyc +0 -0
  132. ksxt/market/krx/__pycache__/kosdaq.cpython-39.pyc +0 -0
  133. ksxt/market/krx/__pycache__/kospi.cpython-39.pyc +0 -0
  134. ksxt/market/krx/__pycache__/stock.cpython-39.pyc +0 -0
  135. ksxt/market/us/__pycache__/amex.cpython-39.pyc +0 -0
  136. ksxt/market/us/__pycache__/nasdaq.cpython-39.pyc +0 -0
  137. ksxt/market/us/__pycache__/nyse.cpython-39.pyc +0 -0
  138. ksxt/market/us/__pycache__/stock.cpython-39.pyc +0 -0
  139. ksxt-0.0.8.dist-info/RECORD +0 -49
  140. {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/LICENSE.txt +0 -0
  141. {ksxt-0.0.8.dist-info → ksxt-0.0.10.dist-info}/top_level.txt +0 -0
ksxt/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
- __version__ = '0.0.2'
1
+ __version__ = "0.0.2"
2
2
 
3
3
  from ksxt.koreainvest import KoreaInvest
4
+ from ksxt.upbit import Upbit
5
+ from ksxt.bithumb import Bithumb
Binary file
Binary file
ksxt/api/__init__.py ADDED
@@ -0,0 +1,26 @@
1
+ import types
2
+
3
+
4
+ class Entry:
5
+ def __init__(self, security_type, path, config):
6
+ # equity, derivative, oversea_equity, oversea_derivative
7
+ self.security_type = security_type
8
+
9
+ # function key
10
+ self.path = path
11
+
12
+ self.config = config
13
+
14
+ def unbound_method(_self, params={}):
15
+ return _self.request(self.path, self.security_type, params, config=self.config)
16
+
17
+ self.unbound_method = unbound_method
18
+
19
+ def __get__(self, instance, owner):
20
+ if instance is None:
21
+ return self.unbound_method
22
+ else:
23
+ return types.MethodType(self.unbound_method, instance)
24
+
25
+ def __set_name__(self, owner, name):
26
+ self.name = name
@@ -0,0 +1,54 @@
1
+ import importlib
2
+
3
+
4
+ def generate_class_code(exchange_name: str):
5
+ try:
6
+ # Dynamically import the module based on the exchange name
7
+ module = importlib.import_module(f"{exchange_name}")
8
+ exchange_methods = module.entries[exchange_name]
9
+ except ImportError:
10
+ raise ValueError(f"Module for exchange '{exchange_name}' could not be found.")
11
+ except AttributeError:
12
+ raise ValueError(f"Entries for exchange '{exchange_name}' not found in the module.")
13
+
14
+ class_code = "class ImplicitAPI:\n"
15
+
16
+ # Calculate maximum length for method names for alignment
17
+ max_length = 0
18
+ for category, methods in exchange_methods.items():
19
+ for access, http_methods in methods.items():
20
+ if isinstance(http_methods, dict):
21
+ for method, paths in http_methods.items():
22
+ max_length = max(max_length, *(len(f"{access}_{method}_{path}") for path in paths))
23
+ elif isinstance(http_methods, list):
24
+ max_length = max(max_length, *(len(f"{access}_{path}") for path in http_methods))
25
+
26
+ for category, methods in exchange_methods.items():
27
+ class_code += f"\n # {category} API methods\n"
28
+ for access, http_methods in methods.items():
29
+ class_code += f"\n # {access} methods\n"
30
+ if isinstance(http_methods, dict):
31
+ for method, paths in http_methods.items():
32
+ class_code += f"\n # {method} requests\n"
33
+ for path in paths:
34
+ entry_name = f"{access}_{method}_{path}"
35
+ # Right-align entry names for better readability
36
+ class_code += f" {entry_name.ljust(max_length)} = Entry('{category}', '{path}', {{}})\n"
37
+ elif isinstance(http_methods, list):
38
+ for path in http_methods:
39
+ entry_name = f"{access}_{path}"
40
+ class_code += f" {entry_name.ljust(max_length)} = Entry('{category}', '{path}', {{}})\n"
41
+
42
+ return class_code
43
+
44
+
45
+ if __name__ == "__main__":
46
+ exchange_names = ["bithumb", "koreainvest", "upbit"] # List of exchanges to generate files for
47
+
48
+ for exchange_name in exchange_names:
49
+ class_code = generate_class_code(exchange_name)
50
+ filename = f"./src/ksxt/api/{exchange_name}.py"
51
+ with open(filename, "w") as file:
52
+ file.write("from ksxt.api import Entry\n")
53
+ file.write("\n")
54
+ file.write(class_code)
@@ -0,0 +1,35 @@
1
+ entries = {
2
+ "bithumb": {
3
+ "stock": {
4
+ "public": {
5
+ "get": [
6
+ "fetch_markets",
7
+ "fetch_security_ohlcv_minute",
8
+ "fetch_security_ohlcv_day",
9
+ "fetch_security_ohlcv_week",
10
+ "fetch_security_ohlcv_month",
11
+ "fetch_ticker_price",
12
+ "fetch_tickers_price",
13
+ "fetch_orderbook",
14
+ "fetch_orderbooks",
15
+ "fetch_security_info",
16
+ ]
17
+ },
18
+ "private": {
19
+ "get": [
20
+ "fetch_balance",
21
+ "fetch_cash",
22
+ "fetch_trade_fee",
23
+ "fetch_opened_order",
24
+ "fetch_opened_order_detail",
25
+ "fetch_closed_order",
26
+ "fetch_closed_order_detail",
27
+ "fetch_withdrawal_history",
28
+ "fetch_deposit_history",
29
+ ],
30
+ "post": ["send_order_entry", "send_order_entry_market", "send_order_exit", "send_order_exit_market"],
31
+ "delete": ["send_cancel_order"],
32
+ },
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,49 @@
1
+ entries = {
2
+ "koreainvest": {
3
+ "stock": {
4
+ "private": {
5
+ "get": [
6
+ "fetch_balance",
7
+ "fetch_cash",
8
+ "fetch_orderbook",
9
+ "fetch_security_info",
10
+ "fetch_ticker_price",
11
+ "fetch_index_ohlcv",
12
+ "fetch_security_ohlcv_day",
13
+ "fetch_security_ohlcv_minute",
14
+ "fetch_security_ohlcv_month",
15
+ "fetch_security_ohlcv_week",
16
+ "fetch_security_ohlcv_year",
17
+ "fetch_closed_order",
18
+ "fetch_opened_order",
19
+ "fetch_pnl",
20
+ "fetch_screener",
21
+ "fetch_screener_list",
22
+ ],
23
+ "post": [
24
+ "send_modify_order",
25
+ "send_cancel_order",
26
+ "send_order_entry",
27
+ "send_order_exit",
28
+ "send_order_loan_entry",
29
+ "send_order_loan_exit",
30
+ ],
31
+ },
32
+ "public": {
33
+ "post": [
34
+ "generate_token",
35
+ "revoke_token",
36
+ ]
37
+ },
38
+ },
39
+ },
40
+ "websocket": {
41
+ "stock": {
42
+ "subscribe": {
43
+ "ticker": ["subscribe_ticker"],
44
+ "trade": ["subscribe_trade"],
45
+ "orderbook": ["subscribe_orderbook"],
46
+ }
47
+ }
48
+ },
49
+ }
ksxt/api/auto/upbit.py ADDED
@@ -0,0 +1,39 @@
1
+ entries = {
2
+ "upbit": {
3
+ "stock": {
4
+ "public": {
5
+ "get": [
6
+ "fetch_markets",
7
+ "fetch_security_ohlcv_minute",
8
+ "fetch_security_ohlcv_day",
9
+ "fetch_security_ohlcv_week",
10
+ "fetch_security_ohlcv_month",
11
+ "fetch_ticker_price",
12
+ "fetch_tickers_price",
13
+ "fetch_orderbook",
14
+ "fetch_orderbooks",
15
+ ]
16
+ },
17
+ "private": {
18
+ "get": [
19
+ "fetch_balance",
20
+ "fetch_cash",
21
+ "fetch_security_info",
22
+ "fetch_trade_fee",
23
+ "fetch_closed_order_detail",
24
+ "fetch_opened_order_detail",
25
+ "fetch_opened_order",
26
+ "fetch_closed_order",
27
+ "fetch_withdrawal_history",
28
+ "fetch_deposit_history",
29
+ ],
30
+ "post": ["send_order_entry", "send_order_entry_market", "send_order_exit", "send_order_exit_market"],
31
+ "delete": ["send_cancel_order"],
32
+ },
33
+ },
34
+ "websocket": {
35
+ "public": ["subscribe_ticker", "subscribe_trade", "subscribe_orderbook", "subscribe_order"],
36
+ "private": ["subscribe_ticker", "subscribe_trade"],
37
+ },
38
+ }
39
+ }
ksxt/api/bithumb.py ADDED
@@ -0,0 +1,42 @@
1
+ from ksxt.api import Entry
2
+
3
+
4
+ class ImplicitAPI:
5
+
6
+ # stock API methods
7
+
8
+ # public methods
9
+
10
+ # get requests
11
+ public_get_fetch_markets = Entry("stock", "fetch_markets", {})
12
+ public_get_fetch_security_ohlcv_minute = Entry("stock", "fetch_security_ohlcv_minute", {})
13
+ public_get_fetch_security_ohlcv_day = Entry("stock", "fetch_security_ohlcv_day", {})
14
+ public_get_fetch_security_ohlcv_week = Entry("stock", "fetch_security_ohlcv_week", {})
15
+ public_get_fetch_security_ohlcv_month = Entry("stock", "fetch_security_ohlcv_month", {})
16
+ public_get_fetch_ticker_price = Entry("stock", "fetch_ticker_price", {})
17
+ public_get_fetch_tickers_price = Entry("stock", "fetch_tickers_price", {})
18
+ public_get_fetch_orderbook = Entry("stock", "fetch_orderbook", {})
19
+ public_get_fetch_orderbooks = Entry("stock", "fetch_orderbooks", {})
20
+ public_get_fetch_security_info = Entry("stock", "fetch_security_info", {})
21
+
22
+ # private methods
23
+
24
+ # get requests
25
+ private_get_fetch_balance = Entry("stock", "fetch_balance", {})
26
+ private_get_fetch_cash = Entry("stock", "fetch_cash", {})
27
+ private_get_fetch_trade_fee = Entry("stock", "fetch_trade_fee", {})
28
+ private_get_fetch_opened_order = Entry("stock", "fetch_opened_order", {})
29
+ private_get_fetch_opened_order_detail = Entry("stock", "fetch_opened_order_detail", {})
30
+ private_get_fetch_closed_order = Entry("stock", "fetch_closed_order", {})
31
+ private_get_fetch_closed_order_detail = Entry("stock", "fetch_closed_order_detail", {})
32
+ private_get_fetch_withdrawal_history = Entry("stock", "fetch_withdrawal_history", {})
33
+ private_get_fetch_deposit_history = Entry("stock", "fetch_deposit_history", {})
34
+
35
+ # post requests
36
+ private_post_send_order_entry = Entry("stock", "send_order_entry", {})
37
+ private_post_send_order_entry_market = Entry("stock", "send_order_entry_market", {})
38
+ private_post_send_order_exit = Entry("stock", "send_order_exit", {})
39
+ private_post_send_order_exit_market = Entry("stock", "send_order_exit_market", {})
40
+
41
+ # delete requests
42
+ private_delete_send_cancel_order = Entry("stock", "send_cancel_order", {})
@@ -0,0 +1,40 @@
1
+ from ksxt.api import Entry
2
+
3
+
4
+ class ImplicitAPI:
5
+
6
+ # stock API methods
7
+
8
+ # private methods
9
+
10
+ # get requests
11
+ private_get_fetch_balance = Entry("stock", "fetch_balance", {})
12
+ private_get_fetch_cash = Entry("stock", "fetch_cash", {})
13
+ private_get_fetch_orderbook = Entry("stock", "fetch_orderbook", {})
14
+ private_get_fetch_security_info = Entry("stock", "fetch_security_info", {})
15
+ private_get_fetch_ticker_price = Entry("stock", "fetch_ticker_price", {})
16
+ private_get_fetch_index_ohlcv = Entry("stock", "fetch_index_ohlcv", {})
17
+ private_get_fetch_security_ohlcv_day = Entry("stock", "fetch_security_ohlcv_day", {})
18
+ private_get_fetch_security_ohlcv_minute = Entry("stock", "fetch_security_ohlcv_minute", {})
19
+ private_get_fetch_security_ohlcv_month = Entry("stock", "fetch_security_ohlcv_month", {})
20
+ private_get_fetch_security_ohlcv_week = Entry("stock", "fetch_security_ohlcv_week", {})
21
+ private_get_fetch_security_ohlcv_year = Entry("stock", "fetch_security_ohlcv_year", {})
22
+ # private_get_fetch_closed_order = Entry('stock', 'fetch_closed_order', {})
23
+ # private_get_fetch_opened_order = Entry('stock', 'fetch_opened_order', {})
24
+ # private_get_fetch_pnl = Entry('stock', 'fetch_pnl', {})
25
+ # private_get_fetch_screener = Entry('stock', 'fetch_screener', {})
26
+ # private_get_fetch_screener_list = Entry('stock', 'fetch_screener_list', {})
27
+
28
+ # post requests
29
+ private_post_send_modify_order = Entry("stock", "send_modify_order", {})
30
+ private_post_send_cancel_order = Entry("stock", "send_cancel_order", {})
31
+ private_post_send_order_entry = Entry("stock", "send_order_entry", {})
32
+ private_post_send_order_exit = Entry("stock", "send_order_exit", {})
33
+ private_post_send_order_loan_entry = Entry("stock", "send_order_loan_entry", {})
34
+ private_post_send_order_loan_exit = Entry("stock", "send_order_loan_exit", {})
35
+
36
+ # public methods
37
+
38
+ # post requests
39
+ public_post_generate_token = Entry("token", "generate_token", {})
40
+ public_post_revoke_token = Entry("token", "revoke_token", {})
ksxt/api/upbit.py ADDED
@@ -0,0 +1,54 @@
1
+ from ksxt.api import Entry
2
+
3
+
4
+ class ImplicitAPI:
5
+
6
+ # stock API methods
7
+
8
+ # public methods
9
+
10
+ # get requests
11
+ public_get_fetch_markets = Entry("stock", "fetch_markets", {})
12
+ public_get_fetch_security_ohlcv_minute = Entry("stock", "fetch_security_ohlcv_minute", {})
13
+ public_get_fetch_security_ohlcv_day = Entry("stock", "fetch_security_ohlcv_day", {})
14
+ public_get_fetch_security_ohlcv_week = Entry("stock", "fetch_security_ohlcv_week", {})
15
+ public_get_fetch_security_ohlcv_month = Entry("stock", "fetch_security_ohlcv_month", {})
16
+ public_get_fetch_ticker_price = Entry("stock", "fetch_ticker_price", {})
17
+ public_get_fetch_tickers_price = Entry("stock", "fetch_tickers_price", {})
18
+ public_get_fetch_orderbook = Entry("stock", "fetch_orderbook", {})
19
+ public_get_fetch_orderbooks = Entry("stock", "fetch_orderbooks", {})
20
+
21
+ # private methods
22
+
23
+ # get requests
24
+ private_get_fetch_balance = Entry("stock", "fetch_balance", {})
25
+ private_get_fetch_cash = Entry("stock", "fetch_cash", {})
26
+ private_get_fetch_security_info = Entry("stock", "fetch_security_info", {})
27
+ private_get_fetch_trade_fee = Entry("stock", "fetch_trade_fee", {})
28
+ private_get_fetch_closed_order_detail = Entry("stock", "fetch_closed_order_detail", {})
29
+ private_get_fetch_opened_order_detail = Entry("stock", "fetch_opened_order_detail", {})
30
+ private_get_fetch_opened_order = Entry("stock", "fetch_opened_order", {})
31
+ private_get_fetch_closed_order = Entry("stock", "fetch_closed_order", {})
32
+ private_get_fetch_withdrawal_history = Entry("stock", "fetch_withdrawal_history", {})
33
+ private_get_fetch_deposit_history = Entry("stock", "fetch_deposit_history", {})
34
+
35
+ # post requests
36
+ private_post_send_order_entry = Entry("stock", "send_order_entry", {})
37
+ private_post_send_order_entry_market = Entry("stock", "send_order_entry_market", {})
38
+ private_post_send_order_exit = Entry("stock", "send_order_exit", {})
39
+ private_post_send_order_exit_market = Entry("stock", "send_order_exit_market", {})
40
+
41
+ # delete requests
42
+ private_delete_send_cancel_order = Entry("stock", "send_cancel_order", {})
43
+
44
+ # websocket API methods
45
+
46
+ # public methods
47
+ public_subscribe_ticker = Entry("websocket", "subscribe_ticker", {})
48
+ public_subscribe_trade = Entry("websocket", "subscribe_trade", {})
49
+ public_subscribe_orderbook = Entry("websocket", "subscribe_orderbook", {})
50
+ public_subscribe_order = Entry("websocket", "subscribe_order", {})
51
+
52
+ # private methods
53
+ private_subscribe_ticker = Entry("websocket", "subscribe_ticker", {})
54
+ private_subscribe_trade = Entry("websocket", "subscribe_trade", {})
@@ -0,0 +1,4 @@
1
+ from ksxt.async_.base.async_exchange import AsyncExchange
2
+ from ksxt.async_.upbit import Upbit
3
+ from ksxt.async_.bithumb import Bithumb
4
+ from ksxt.async_.koreainvest import KoreaInvest
File without changes
@@ -0,0 +1,232 @@
1
+ import asyncio
2
+ import aiohttp
3
+ import json
4
+ import os
5
+ import platform
6
+ import tomllib
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+ from typing import Any, Dict, Literal, Optional
10
+
11
+ import yarl
12
+
13
+ from ksxt.async_.base.throttler import Throttler
14
+ from ksxt.base.errors import NotSupportedError
15
+ from ksxt.base.rest_exchange import RestExchange
16
+ from ksxt.config import CONFIG_DIR
17
+ import ksxt.models
18
+
19
+
20
+ class AsyncExchange(RestExchange):
21
+ synchronous = False
22
+
23
+ def __init__(self, config: Dict = None, filename: str = None):
24
+ super().__init__(config, filename)
25
+
26
+ self.asyncio_loop = asyncio.get_event_loop()
27
+ self.session = aiohttp.ClientSession()
28
+ self.throttle = Throttler({}, self.asyncio_loop)
29
+
30
+ async def initialize(self):
31
+ if self.asyncio_loop is None:
32
+ self.asyncio_loop = asyncio.get_event_loop()
33
+ if self.session is None:
34
+ self.session = aiohttp.ClientSession()
35
+ if self.throttle is None:
36
+ self.throttle = Throttler({}, self.asyncio_loop)
37
+
38
+ async def close(self):
39
+ if self.session:
40
+ await self.session.close()
41
+ self.session = None
42
+
43
+ async def __aenter__(self):
44
+ await self.initialize()
45
+ return self
46
+
47
+ async def __aexit__(self, *args):
48
+ await self.close()
49
+
50
+ def _get_api_from_file(self, filename: str):
51
+ if filename is None:
52
+ tr_config_filename = "tr_dev.json" if self.is_dev else "tr_app.json"
53
+ else:
54
+ tr_config_filename = filename
55
+
56
+ config_path = os.path.join(CONFIG_DIR, tr_config_filename)
57
+
58
+ if Path(tr_config_filename).suffix == ".json":
59
+ with open(
60
+ config_path,
61
+ encoding="utf-8",
62
+ ) as f:
63
+ c = json.load(f)
64
+ return {"apis": c[self.name]}
65
+
66
+ elif Path(tr_config_filename).suffix == ".toml":
67
+ with open(config_path, mode="rb") as f:
68
+ c = tomllib.load(f)
69
+ return c
70
+
71
+ async def fetch(self, url, method="GET", headers=None, body=None, params=None):
72
+ request_headers = headers
73
+ request_body = str(body).encode() if body else None
74
+ request_params = params
75
+
76
+ session_method = getattr(self.session, method.lower())
77
+
78
+ try:
79
+ async with session_method(
80
+ url,
81
+ # yarl.URL(url, encoded=True),
82
+ headers=request_headers,
83
+ data=request_body,
84
+ params=request_params,
85
+ timeout=aiohttp.ClientTimeout(total=int(self.timeout / 1000)),
86
+ ) as response:
87
+ http_response = await response.text(errors="replace")
88
+ json_response = self.parse_json(http_response)
89
+ return json_response
90
+ except asyncio.TimeoutError as e:
91
+ details = f"{self.id} {method} {url}"
92
+ raise TimeoutError(details) from e
93
+
94
+ async def fetch2(
95
+ self, path, security_type, params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}
96
+ ):
97
+ is_activate = self.apis[self.type][security_type][path]["activate"]
98
+ if not is_activate:
99
+ return {
100
+ "response": {
101
+ # 성공 실패 여부
102
+ "success": "-1",
103
+ # 응답코드
104
+ "code": "fail",
105
+ # 응답메세지
106
+ "message": f"지원하지 않는 함수({path}) 입니다.",
107
+ }
108
+ }
109
+
110
+ # if self.enableRateLimit:
111
+ # cost = self.calculate_rate_limiter_cost(api, method, path, params, config)
112
+ # self.throttle(cost)
113
+
114
+ # self.lastRestRequestTimestamp = self.milliseconds()
115
+
116
+ method_type = self.apis[self.type][security_type][path]["method"]
117
+ api_type = self.apis[self.type][security_type][path]["api"]
118
+ request = self.sign(path, security_type, method_type, api_type, headers, body, params, config)
119
+ return await self.fetch(
120
+ request["url"], request["method"], request["headers"], request["body"], request["params"]
121
+ )
122
+
123
+ # region base method
124
+ async def fetch_markets(self, market_name: str) -> ksxt.models.KsxtMarketResponse:
125
+ raise NotSupportedError(f"{self.id} {self.fetch_markets.__qualname__}() is not supported yet.")
126
+
127
+ async def fetch_security(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSecurityResponse:
128
+ raise NotSupportedError(f"{self.id} {self.fetch_security.__qualname__}() is not supported yet.")
129
+
130
+ async def fetch_ticker(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtTickerResponse:
131
+ raise NotSupportedError(f"{self.id} {self.fetch_ticker.__qualname__}() is not supported yet.")
132
+
133
+ async def fetch_orderbook(self, symbol: str, base_market: str = "KRW") -> ksxt.models.KsxtSingleOrderBookResponse:
134
+ raise NotSupportedError(f"{self.id} {self.fetch_orderbook.__qualname__}() is not supported yet.")
135
+
136
+ async def fetch_historical_data(
137
+ self,
138
+ symbol: str,
139
+ time_frame: str,
140
+ start: Optional[str] = None,
141
+ end: Optional[str] = None,
142
+ base_market: str = "KRW",
143
+ ) -> ksxt.models.KsxtHistoricalDataResponse:
144
+ raise NotSupportedError(f"{self.id} {self.fetch_historical_data.__qualname__}() is not supported yet.")
145
+
146
+ async def fetch_is_holiday(self, dt: datetime, base_market: str = "KRW"):
147
+ raise NotSupportedError(f"{self.id} {self.fetch_is_holiday.__qualname__}() is not supported yet.")
148
+
149
+ async def fetch_user_info(self, base_market: str = "KRW"):
150
+ raise NotSupportedError(f"{self.id} {self.fetch_user_info.__qualname__}() is not supported yet.")
151
+
152
+ async def fetch_balance(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtBalanceResponse:
153
+ raise NotSupportedError(f"{self.id} {self.fetch_balance.__qualname__}() is not supported yet.")
154
+
155
+ async def fetch_cash(self, acc_num: str, base_market: str = "KRW") -> ksxt.models.KsxtCashResponse:
156
+ raise NotSupportedError(f"{self.id} {self.fetch_cash.__qualname__}() is not supported yet.")
157
+
158
+ async def fetch_screener_list(self, base_market: str = "KRW"):
159
+ raise NotSupportedError(f"{self.id} {self.fetch_screener_list.__qualname__}() is not supported yet.")
160
+
161
+ async def fetch_screener(self, screen_id: str, base_market: str = "KRW"):
162
+ raise NotSupportedError(f"{self.id} {self.fetch_screener.__qualname__}() is not supported yet.")
163
+
164
+ async def fetch_deposit_history(
165
+ self, acc_num: str, base_market: str = "KRW"
166
+ ) -> ksxt.models.KsxtDepositHistoryResponse:
167
+ raise NotSupportedError(f"{self.id} {self.fetch_deposit_history.__qualname__}() is not supported yet.")
168
+
169
+ async def fetch_withdrawal_history(
170
+ self, acc_num: str, base_market: str = "KRW"
171
+ ) -> ksxt.models.KsxtWithdrawalHistoryResponse:
172
+ raise NotSupportedError(f"{self.id} {self.fetch_withdrawal_history.__qualname__}() is not supported yet.")
173
+
174
+ async def create_order(
175
+ self,
176
+ acc_num: str,
177
+ symbol: str,
178
+ ticket_type: Literal["EntryLong", "EntryShort", "ExitLong", "ExitShort"],
179
+ otype: Literal["limit", "market"],
180
+ price: Optional[float] = 0,
181
+ qty: Optional[float] = 0,
182
+ amount: Optional[float] = 0,
183
+ base_market: str = "KRW",
184
+ ) -> ksxt.models.KsxtCreateOrderResponse:
185
+ raise NotSupportedError(f"{self.id} {self.create_order.__qualname__}() is not supported yet.")
186
+
187
+ async def cancel_order(
188
+ self, acc_num: str, order_id: str, symbol: Optional[str] = "", qty: float = 0, *args, base_market: str = "KRW"
189
+ ) -> ksxt.models.KsxtCancelOrderResponse:
190
+ raise NotSupportedError(f"{self.id} {self.cancel_order.__qualname__}() is not supported yet.")
191
+
192
+ async def modify_order(
193
+ self,
194
+ acc_num: str,
195
+ order_id: str,
196
+ price: float,
197
+ qty: float,
198
+ *args,
199
+ symbol: Optional[str] = "",
200
+ base_market: str = "KRW",
201
+ ):
202
+ raise NotSupportedError(f"{self.id} {self.modify_order.__qualname__}() is not supported yet.")
203
+
204
+ async def fetch_open_order(
205
+ self,
206
+ acc_num: str,
207
+ symbol: Optional[str] = "",
208
+ start: Optional[str] = None,
209
+ end: Optional[str] = None,
210
+ base_market: str = "KRW",
211
+ ) -> ksxt.models.KsxtOpenOrderResponse:
212
+ raise NotSupportedError(f"{self.id} {self.fetch_open_order.__qualname__}() is not supported yet.")
213
+
214
+ async def fetch_closed_order(
215
+ self,
216
+ acc_num: str,
217
+ symbol: Optional[str] = "",
218
+ start: Optional[str] = None,
219
+ end: Optional[str] = None,
220
+ base_market: str = "KRW",
221
+ ) -> ksxt.models.KsxtClosedOrderResponse:
222
+ raise NotSupportedError(f"{self.id} {self.fetch_closed_order.__qualname__}() is not supported yet.")
223
+
224
+ async def reserve_order(
225
+ self, acc_num: str, symbol: str, price: float, qty: float, target_date: str, base_market: str = "KRW"
226
+ ):
227
+ raise NotSupportedError(f"{self.id} {self.reserve_order.__qualname__}() is not supported yet.")
228
+
229
+ # endregion base method
230
+
231
+ async def sleep(self, milliseconds):
232
+ return await asyncio.sleep(milliseconds / 1000)