ksxt 0.0.10__py3-none-any.whl → 1.0.1__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__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/__pycache__/koreainvest.cpython-312.pyc +0 -0
- ksxt/async_/base/__pycache__/async_exchange.cpython-312.pyc +0 -0
- ksxt/async_/base/async_exchange.py +35 -42
- ksxt/async_/koreainvest.py +271 -639
- 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/exchange.py +5 -0
- ksxt/base/rate_limiter.py +88 -0
- ksxt/base/rest_exchange.py +52 -26
- ksxt/config/__init__.py +2 -0
- ksxt/config/__pycache__/__init__.cpython-312.pyc +0 -0
- ksxt/config/bithumb.toml +2 -1
- ksxt/config/upbit.toml +6 -1
- ksxt/koreainvest.py +6 -26
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/METADATA +1 -1
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/RECORD +21 -20
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/WHEEL +1 -1
- ksxt/async_/base/throttler.py +0 -63
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/LICENSE.txt +0 -0
- {ksxt-0.0.10.dist-info → ksxt-1.0.1.dist-info}/top_level.txt +0 -0
Binary file
|
Binary file
|
Binary file
|
@@ -1,19 +1,14 @@
|
|
1
1
|
import asyncio
|
2
|
+
import time
|
2
3
|
import aiohttp
|
3
|
-
import json
|
4
|
-
import os
|
5
|
-
import platform
|
6
|
-
import tomllib
|
7
4
|
from datetime import datetime
|
8
|
-
from pathlib import Path
|
9
5
|
from typing import Any, Dict, Literal, Optional
|
10
6
|
|
11
|
-
import yarl
|
12
7
|
|
13
|
-
from ksxt.async_.base.throttler import Throttler
|
14
8
|
from ksxt.base.errors import NotSupportedError
|
9
|
+
from ksxt.base.rate_limiter import RateLimiterContext
|
15
10
|
from ksxt.base.rest_exchange import RestExchange
|
16
|
-
from ksxt.config import
|
11
|
+
from ksxt.config import VALID_METHODS
|
17
12
|
import ksxt.models
|
18
13
|
|
19
14
|
|
@@ -23,22 +18,26 @@ class AsyncExchange(RestExchange):
|
|
23
18
|
def __init__(self, config: Dict = None, filename: str = None):
|
24
19
|
super().__init__(config, filename)
|
25
20
|
|
26
|
-
self.asyncio_loop =
|
27
|
-
self.session
|
28
|
-
self.throttle = Throttler({}, self.asyncio_loop)
|
21
|
+
self.asyncio_loop = None
|
22
|
+
self.session: aiohttp.ClientSession = None
|
29
23
|
|
30
24
|
async def initialize(self):
|
31
25
|
if self.asyncio_loop is None:
|
32
26
|
self.asyncio_loop = asyncio.get_event_loop()
|
33
|
-
|
27
|
+
|
28
|
+
if self.session is None or (
|
29
|
+
self.session_last_used and (time.time() - self.session_last_used > self.session_lifetime)
|
30
|
+
):
|
31
|
+
if self.session:
|
32
|
+
await self.session.close()
|
34
33
|
self.session = aiohttp.ClientSession()
|
35
|
-
|
36
|
-
self.throttle = Throttler({}, self.asyncio_loop)
|
34
|
+
self.session_last_used = time.time()
|
37
35
|
|
38
36
|
async def close(self):
|
39
37
|
if self.session:
|
40
38
|
await self.session.close()
|
41
39
|
self.session = None
|
40
|
+
self.session_last_used = None
|
42
41
|
|
43
42
|
async def __aenter__(self):
|
44
43
|
await self.initialize()
|
@@ -47,49 +46,43 @@ class AsyncExchange(RestExchange):
|
|
47
46
|
async def __aexit__(self, *args):
|
48
47
|
await self.close()
|
49
48
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
else:
|
54
|
-
tr_config_filename = filename
|
55
|
-
|
56
|
-
config_path = os.path.join(CONFIG_DIR, tr_config_filename)
|
49
|
+
async def fetch(self, url, method="GET", headers=None, body=None, params=None):
|
50
|
+
# Ensure that resources are initialized before the request
|
51
|
+
await self.initialize()
|
57
52
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
encoding="utf-8",
|
62
|
-
) as f:
|
63
|
-
c = json.load(f)
|
64
|
-
return {"apis": c[self.name]}
|
53
|
+
method_lower = method.lower()
|
54
|
+
if method_lower not in VALID_METHODS:
|
55
|
+
raise ValueError(f"Invalid HTTP method: {method}")
|
65
56
|
|
66
|
-
|
67
|
-
with open(config_path, mode="rb") as f:
|
68
|
-
c = tomllib.load(f)
|
69
|
-
return c
|
57
|
+
session_method = getattr(self.session, method.lower())
|
70
58
|
|
71
|
-
|
72
|
-
|
73
|
-
request_body = str(body).encode() if body else None
|
74
|
-
request_params = params
|
59
|
+
# TODO : Set rate limiters value when config load
|
60
|
+
api_name = ""
|
75
61
|
|
76
|
-
|
62
|
+
if api_name and api_name in self.rate_limiters:
|
63
|
+
await self.rate_limiters[api_name].async_acquire()
|
77
64
|
|
78
65
|
try:
|
79
66
|
async with session_method(
|
80
67
|
url,
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
params=request_params,
|
68
|
+
headers=headers,
|
69
|
+
data=str(body).encode() if body else None,
|
70
|
+
params=params,
|
85
71
|
timeout=aiohttp.ClientTimeout(total=int(self.timeout / 1000)),
|
86
72
|
) as response:
|
87
73
|
http_response = await response.text(errors="replace")
|
88
74
|
json_response = self.parse_json(http_response)
|
89
75
|
return json_response
|
90
|
-
except asyncio.TimeoutError as e:
|
76
|
+
except (asyncio.TimeoutError, aiohttp.ClientError) as e:
|
91
77
|
details = f"{self.id} {method} {url}"
|
92
78
|
raise TimeoutError(details) from e
|
79
|
+
finally:
|
80
|
+
if (
|
81
|
+
api_name
|
82
|
+
and api_name in self.rate_limiters
|
83
|
+
and isinstance(self.rate_limiters[api_name], RateLimiterContext)
|
84
|
+
):
|
85
|
+
self.rate_limiters[api_name].release()
|
93
86
|
|
94
87
|
async def fetch2(
|
95
88
|
self, path, security_type, params={}, headers: Optional[Any] = None, body: Optional[Any] = None, config={}
|