hyperquant 0.1.1__tar.gz → 0.1.3__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: A minimal yet hyper-efficient backtesting framework for quantitative trading
5
5
  Project-URL: Homepage, https://github.com/yourusername/hyperquant
6
6
  Project-URL: Issues, https://github.com/yourusername/hyperquant/issues
@@ -12,8 +12,11 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Topic :: Office/Business :: Financial :: Investment
15
- Requires-Python: >=3.8
15
+ Requires-Python: >=3.9
16
+ Requires-Dist: aiohttp>=3.11.16
16
17
  Requires-Dist: colorama>=0.4.6
18
+ Requires-Dist: cryptography>=44.0.2
19
+ Requires-Dist: numpy>=1.21.0
17
20
  Requires-Dist: pandas>=2.2.3
18
21
  Requires-Dist: pyecharts>=2.0.8
19
22
  Description-Content-Type: text/markdown
@@ -3,11 +3,11 @@ echo "清理旧的构建文件..."
3
3
  rm -rf dist/* build/*
4
4
 
5
5
  echo "重新构建包..."
6
- rye build
6
+ uv build
7
7
 
8
8
  echo "发布到 PyPI..."
9
9
  # 从 .pypirc 文件读取 token
10
10
  TOKEN=$(grep "password" .pypirc | cut -d "=" -f2 | tr -d ' ')
11
11
 
12
12
  # 使用 token 发布
13
- TWINE_USERNAME=__token__ TWINE_PASSWORD=$TOKEN rye run twine upload dist/*
13
+ TWINE_USERNAME=__token__ TWINE_PASSWORD=$TOKEN uv run twine upload dist/*
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -9,9 +9,12 @@ dependencies = [
9
9
  "pyecharts>=2.0.8",
10
10
  "pandas>=2.2.3",
11
11
  "colorama>=0.4.6",
12
+ "aiohttp>=3.11.16",
13
+ "cryptography>=44.0.2",
14
+ "numpy>=1.21.0", # Added numpy as a new dependency
12
15
  ]
13
16
  readme = "README.md"
14
- requires-python = ">= 3.8"
17
+ requires-python = ">= 3.9"
15
18
  keywords = ["quant", "backtesting", "trading", "hyperquant"]
16
19
  license = {text = "MIT"}
17
20
  classifiers = [
@@ -30,12 +33,13 @@ Issues = "https://github.com/yourusername/hyperquant/issues"
30
33
  requires = ["hatchling"]
31
34
  build-backend = "hatchling.build"
32
35
 
33
- [tool.rye]
34
- managed = true
35
- dev-dependencies = ["twine>=6.1.0"]
36
-
37
36
  [tool.hatch.metadata]
38
37
  allow-direct-references = true
39
38
 
40
39
  [tool.hatch.build.targets.wheel]
41
- packages = ["src/hyperquant"]
40
+ packages = ["src/hyperquant"]
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "twine>=6.1.0",
45
+ ]
@@ -10,18 +10,34 @@
10
10
  # universal: false
11
11
 
12
12
  -e file:.
13
+ aiohappyeyeballs==2.6.1
14
+ # via aiohttp
15
+ aiohttp==3.11.16
16
+ # via hyperquant
17
+ aiosignal==1.3.2
18
+ # via aiohttp
19
+ attrs==25.3.0
20
+ # via aiohttp
13
21
  certifi==2025.1.31
14
22
  # via requests
23
+ cffi==1.17.1
24
+ # via cryptography
15
25
  charset-normalizer==3.4.1
16
26
  # via requests
17
27
  colorama==0.4.6
18
- # via minbacktest
28
+ # via hyperquant
29
+ cryptography==44.0.2
30
+ # via hyperquant
19
31
  docutils==0.21.2
20
32
  # via readme-renderer
33
+ frozenlist==1.6.0
34
+ # via aiohttp
35
+ # via aiosignal
21
36
  id==1.5.0
22
37
  # via twine
23
38
  idna==3.10
24
39
  # via requests
40
+ # via yarl
25
41
  jaraco-classes==3.4.0
26
42
  # via keyring
27
43
  jaraco-context==6.0.1
@@ -41,6 +57,9 @@ mdurl==0.1.2
41
57
  more-itertools==10.6.0
42
58
  # via jaraco-classes
43
59
  # via jaraco-functools
60
+ multidict==6.4.3
61
+ # via aiohttp
62
+ # via yarl
44
63
  nh3==0.2.21
45
64
  # via readme-renderer
46
65
  numpy==2.2.4
@@ -48,11 +67,16 @@ numpy==2.2.4
48
67
  packaging==24.2
49
68
  # via twine
50
69
  pandas==2.2.3
51
- # via minbacktest
70
+ # via hyperquant
52
71
  prettytable==3.15.1
53
72
  # via pyecharts
73
+ propcache==0.3.1
74
+ # via aiohttp
75
+ # via yarl
76
+ pycparser==2.22
77
+ # via cffi
54
78
  pyecharts==2.0.8
55
- # via minbacktest
79
+ # via hyperquant
56
80
  pygments==2.19.1
57
81
  # via readme-renderer
58
82
  # via rich
@@ -84,3 +108,5 @@ urllib3==2.3.0
84
108
  # via twine
85
109
  wcwidth==0.2.13
86
110
  # via prettytable
111
+ yarl==1.20.0
112
+ # via aiohttp
@@ -10,20 +10,45 @@
10
10
  # universal: false
11
11
 
12
12
  -e file:.
13
+ aiohappyeyeballs==2.6.1
14
+ # via aiohttp
15
+ aiohttp==3.11.16
16
+ # via hyperquant
17
+ aiosignal==1.3.2
18
+ # via aiohttp
19
+ attrs==25.3.0
20
+ # via aiohttp
21
+ cffi==1.17.1
22
+ # via cryptography
13
23
  colorama==0.4.6
14
- # via minbacktest
24
+ # via hyperquant
25
+ cryptography==44.0.2
26
+ # via hyperquant
27
+ frozenlist==1.6.0
28
+ # via aiohttp
29
+ # via aiosignal
30
+ idna==3.10
31
+ # via yarl
15
32
  jinja2==3.1.6
16
33
  # via pyecharts
17
34
  markupsafe==3.0.2
18
35
  # via jinja2
36
+ multidict==6.4.3
37
+ # via aiohttp
38
+ # via yarl
19
39
  numpy==2.2.4
20
40
  # via pandas
21
41
  pandas==2.2.3
22
- # via minbacktest
42
+ # via hyperquant
23
43
  prettytable==3.15.1
24
44
  # via pyecharts
45
+ propcache==0.3.1
46
+ # via aiohttp
47
+ # via yarl
48
+ pycparser==2.22
49
+ # via cffi
25
50
  pyecharts==2.0.8
26
- # via minbacktest
51
+ # via hyperquant
27
52
  python-dateutil==2.9.0.post0
28
53
  # via pandas
29
54
  pytz==2025.1
@@ -36,3 +61,5 @@ tzdata==2025.1
36
61
  # via pandas
37
62
  wcwidth==0.2.13
38
63
  # via prettytable
64
+ yarl==1.20.0
65
+ # via aiohttp
@@ -1,5 +1,5 @@
1
1
  from .core import *
2
2
  from .draw import *
3
3
  from .logkit import *
4
-
4
+ from .datavison import *
5
5
  __version__ = "0.1.0"
@@ -0,0 +1,18 @@
1
+ from datetime import date, datetime
2
+
3
+
4
+ def _to_milliseconds( t):
5
+ """
6
+ 支持毫秒时间戳或datetime/date类型,返回毫秒时间戳
7
+ """
8
+ if t is None:
9
+ return None
10
+ if isinstance(t, int):
11
+ return t
12
+ if isinstance(t, float):
13
+ return int(t * 1000)
14
+ if isinstance(t, datetime):
15
+ return int(t.timestamp() * 1000)
16
+ if isinstance(t, date):
17
+ return int(datetime.combine(t, datetime.min.time()).timestamp() * 1000)
18
+ raise ValueError(f"不支持的时间类型: {type(t)}")
@@ -0,0 +1,62 @@
1
+ import aiohttp
2
+ import asyncio
3
+ from datetime import datetime, date, timedelta
4
+ # from _util import _to_milliseconds
5
+ from ._util import _to_milliseconds
6
+ import pandas as pd
7
+
8
+ class BinanceSwap:
9
+ def __init__(self) -> None:
10
+ self.session = aiohttp.ClientSession()
11
+
12
+ async def get_klines(self, symbol: str, interval: str, start_time, end_time = None, limit: int = 1500):
13
+ """
14
+ 获取U本位合约K线数据,支持获取任意长度(自动分批)
15
+
16
+ :param symbol: 交易对, 如 'BTCUSDT'
17
+ :param interval: K线间隔, 如 '1m', '5m', '1h', '1d'
18
+ :param start_time: 开始时间, 毫秒时间戳或datetime/date类型
19
+ :param end_time: 结束时间, 毫秒时间戳或datetime/date类型, 默认为None表示最新
20
+ :param limit: 每次请求最大K线数量, 最大1500
21
+ :return: K线数据DataFrame
22
+ """
23
+ url = "https://fapi.binance.com/fapi/v1/klines"
24
+ all_klines = []
25
+ fetch_start = _to_milliseconds(start_time)
26
+ ms_end_time = _to_milliseconds(end_time) if end_time else None
27
+ while True:
28
+ params = {
29
+ "symbol": symbol.upper(),
30
+ "interval": interval,
31
+ "startTime": fetch_start,
32
+ "limit": limit
33
+ }
34
+ if ms_end_time:
35
+ params["endTime"] = ms_end_time
36
+ async with self.session.get(url, params=params) as resp:
37
+ resp.raise_for_status()
38
+ data = await resp.json()
39
+ if not data:
40
+ break
41
+ all_klines.extend(data)
42
+ if len(data) < limit:
43
+ break
44
+ last_open_time = data[-1][0]
45
+ fetch_start = last_open_time + 1
46
+ if ms_end_time and fetch_start >= ms_end_time:
47
+ break
48
+ # 转为DataFrame
49
+ columns = [
50
+ "open_time", "open", "high", "low", "close", "volume",
51
+ "close_time", "quote_asset_volume", "number_of_trades",
52
+ "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume", "ignore"
53
+ ]
54
+ df = pd.DataFrame(all_klines, columns=columns)
55
+ # 类型转换
56
+ df["open_time"] = pd.to_datetime(df["open_time"], unit="ms")
57
+ df["close_time"] = pd.to_datetime(df["close_time"], unit="ms")
58
+ for col in ["open", "high", "low", "close", "volume", "quote_asset_volume", "taker_buy_base_asset_volume", "taker_buy_quote_asset_volume"]:
59
+ df[col] = pd.to_numeric(df[col], errors="coerce")
60
+ df["number_of_trades"] = df["number_of_trades"].astype(int)
61
+ return df
62
+
@@ -0,0 +1,237 @@
1
+ """
2
+ Coinglass API 数据解密与数据获取模块
3
+ 优化:
4
+ - 只保留必要依赖,整理import顺序
5
+ - 增加类型注解和文档
6
+ - 统一异常处理和日志输出
7
+ - 精简冗余代码
8
+ """
9
+ import asyncio
10
+ import base64
11
+ import json
12
+ import struct
13
+ import time
14
+ import zlib
15
+ import hmac
16
+ import hashlib
17
+ from datetime import datetime, timedelta
18
+ from typing import Any, Dict, List, Optional, Union
19
+ import pandas as pd # type: ignore
20
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
21
+ from cryptography.hazmat.primitives import padding as crypto_padding
22
+ from cryptography.hazmat.backends import default_backend
23
+ import aiohttp
24
+
25
+ # ------------------ 工具函数 ------------------
26
+ class CustomParser:
27
+ @staticmethod
28
+ def parse(data: str) -> Dict[str, Union[List[int], int]]:
29
+ """
30
+ 将字符串转换为数字数组,兼容原始加密逻辑。
31
+ """
32
+ length = len(data)
33
+ n = [0] * ((length + 3) // 4)
34
+ for r in range(length):
35
+ n[r >> 2] |= (ord(data[r]) & 255) << (24 - (r % 4) * 8)
36
+ return {"n": n, "e": length}
37
+
38
+ def convert_words_to_bytes(words: List[int]) -> bytes:
39
+ """
40
+ 将整数数组转换为字节数组。
41
+ """
42
+ return b"".join(struct.pack(">I", word) for word in words)
43
+
44
+ def decrypt_and_clean(t: str, e: Dict[str, Any]) -> str:
45
+ """
46
+ 解密、解压缩并清理输入字符串。
47
+ """
48
+ aes_key = convert_words_to_bytes(e['n'])
49
+ cipher = Cipher(algorithms.AES(aes_key), modes.ECB(), backend=default_backend())
50
+ decryptor = cipher.decryptor()
51
+ encrypted_data = base64.b64decode(t)
52
+ decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
53
+ unpadder = crypto_padding.PKCS7(128).unpadder()
54
+ unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()
55
+ decompressed_data = zlib.decompress(unpadded_data, wbits=16 + zlib.MAX_WBITS).decode('utf-8')
56
+ return decompressed_data
57
+
58
+ def generate_totp(secret: str, for_time: int, interval: int = 30, digits: int = 6, digest=hashlib.sha1) -> str:
59
+ """
60
+ 基于标准库的TOTP实现。
61
+ """
62
+ key = base64.b32decode(secret, casefold=True)
63
+ counter = int(for_time // interval)
64
+ msg = counter.to_bytes(8, 'big')
65
+ h = hmac.new(key, msg, digest).digest()
66
+ o = h[-1] & 0x0F
67
+ code = (struct.unpack('>I', h[o:o+4])[0] & 0x7fffffff) % (10 ** digits)
68
+ return str(code).zfill(digits)
69
+
70
+ def generate_encrypted_token() -> str:
71
+ """
72
+ 生成加密token,用于API请求。
73
+ """
74
+ current_time = int(time.time())
75
+ secret_key = "I65VU7K5ZQL7WB4E"
76
+ otp = generate_totp(secret_key, current_time)
77
+ combined_string = f"{current_time},{otp}"
78
+ aes_key = "1f68efd73f8d4921acc0dead41dd39bc"
79
+ aes_key_bytes = CustomParser.parse(aes_key)
80
+ final_key = convert_words_to_bytes(aes_key_bytes['n'])
81
+ cipher = Cipher(algorithms.AES(final_key), modes.ECB(), backend=default_backend())
82
+ encryptor = cipher.encryptor()
83
+ padder = crypto_padding.PKCS7(128).padder()
84
+ padded_data = padder.update(combined_string.encode('utf-8')) + padder.finalize()
85
+ encrypted_bytes = encryptor.update(padded_data) + encryptor.finalize()
86
+ return base64.b64encode(encrypted_bytes).decode('utf-8')
87
+
88
+ def decrypt_coinglass(data: str, user_header: str, url: str) -> str:
89
+ """
90
+ 解密 Coinglass API 的响应数据。
91
+ """
92
+ base_key = base64.b64encode(f"coinglass{url}coinglass".encode("utf-8")).decode("utf-8")[:16]
93
+ processed_key = CustomParser.parse(base_key)
94
+ decrypted_key = decrypt_and_clean(user_header, processed_key)
95
+ session_key = decrypt_and_clean(data, CustomParser.parse(decrypted_key))
96
+ return session_key
97
+
98
+ # ------------------ API类 ------------------
99
+ HEADERS = {
100
+ 'accept': 'application/json',
101
+ 'accept-language': 'en-US,en;q=0.9',
102
+ 'cache-ts': str(int(time.time() * 1000)),
103
+ 'dnt': '1',
104
+ 'encryption': 'true',
105
+ 'language': 'en',
106
+ 'origin': 'https://www.coinglass.com',
107
+ 'priority': 'u=1, i',
108
+ 'referer': 'https://www.coinglass.com/',
109
+ 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
110
+ 'sec-ch-ua-mobile': '?0',
111
+ 'sec-ch-ua-platform': '"Windows"',
112
+ 'sec-fetch-dest': 'empty',
113
+ 'sec-fetch-mode': 'cors',
114
+ 'sec-fetch-site': 'same-site',
115
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
116
+ }
117
+
118
+ class CoinglassApi:
119
+ def __init__(self) -> None:
120
+ self.session = aiohttp.ClientSession()
121
+
122
+ async def connect(self):
123
+ pass
124
+
125
+ async def dec_data(self, response: aiohttp.ClientResponse) -> Optional[Any]:
126
+ try:
127
+ encrypted_data = (await response.json())['data']
128
+ requests_url = response.url.path
129
+ encrypted_user_header = response.headers.get("user", "HEADERNOTFOUND")
130
+ decrypted = decrypt_coinglass(encrypted_data, encrypted_user_header, requests_url)
131
+ return json.loads(decrypted)
132
+ except Exception as e:
133
+ print(f"解密失败: {e}")
134
+ return None
135
+
136
+ async def fetch_base_klines(self, symbol: str, start_time: datetime, end_time: Optional[datetime] = None, ktype: str = '#coin#oi_kline', interval: str = 'm1') -> Any:
137
+ start_ts = int(start_time.timestamp())
138
+ end_ts = int(end_time.timestamp()) if end_time else int(time.time())
139
+ url = 'https://fapi.coinglass.com/api/v2/kline'
140
+ params = {
141
+ 'symbol': f'{symbol}{ktype}',
142
+ 'interval': interval,
143
+ 'endTime': end_ts,
144
+ 'startTime': start_ts,
145
+ 'minLimit': 'false',
146
+ }
147
+ async with self.session.get(url, params=params, headers=HEADERS) as response:
148
+ if response.status == 200:
149
+ return await self.dec_data(response)
150
+ print(f"请求失败,状态码: {response.status}: {await response.text()}")
151
+ return pd.DataFrame()
152
+
153
+ async def fetch_price_klines(self, symbol: str, start_time: datetime, end_time: Optional[datetime] = None, interval: str = 'm5') -> pd.DataFrame:
154
+ data = await self.fetch_base_klines(symbol, start_time, end_time, '#kline', interval)
155
+ df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
156
+ df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
157
+ df['timestamp'] = pd.to_datetime(df['timestamp'], unit="s", utc=True)
158
+ df['symbol'] = symbol
159
+ return df
160
+
161
+ async def fetch_top_account_klines(self, symbol: str, start_time: datetime, end_time: Optional[datetime] = None, interval: str = 'm5') -> Optional[pd.DataFrame]:
162
+ end_ts = int(end_time.timestamp()) if end_time else int(time.time())
163
+ start_ts = int(start_time.timestamp())
164
+ url = 'https://fapi.coinglass.com/api/v2/kline'
165
+ params = {
166
+ 'symbol': f'{symbol}#top_account_kline',
167
+ 'interval': interval,
168
+ 'endTime': end_ts,
169
+ 'startTime': start_ts,
170
+ 'minLimit': 'false',
171
+ }
172
+ async with self.session.get(url, params=params, headers=HEADERS) as response:
173
+ if response.status == 200:
174
+ data = await self.dec_data(response)
175
+ columns = ['timestamp', 'ratio', 'long_ratio', 'short_ratio']
176
+ df = pd.DataFrame(data, columns=columns)
177
+ df['timestamp'] = pd.to_datetime(df['timestamp'], unit="s", utc=True)
178
+ df[['ratio', 'long_ratio', 'short_ratio']] = df[['ratio', 'long_ratio', 'short_ratio']].astype(float)
179
+ df['symbol'] = symbol
180
+ return df
181
+ print(f"请求失败,状态码: {response.status}: {await response.text()}")
182
+ return None
183
+
184
+ async def fetch_oi_klines(self, symbol: str, start_time: datetime, end_time: Optional[datetime] = None, interval: str = 'm5') -> pd.DataFrame:
185
+ data = await self.fetch_base_klines(symbol, start_time, end_time, '#coin#oi_kline', interval)
186
+ df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close'])
187
+ df[['open', 'high', 'low', 'close']] = df[['open', 'high', 'low', 'close']].astype(float)
188
+ df['timestamp'] = pd.to_datetime(df['timestamp'], unit="s", utc=True)
189
+ df['symbol'] = symbol
190
+ return df
191
+
192
+ async def fetch_liq_klines(self, symbol: str, start_time: datetime, end_time: Optional[datetime] = None, interval: str = 'm5') -> pd.DataFrame:
193
+ data = await self.fetch_base_klines(symbol, start_time, end_time, '#aggregated_liq_kline', interval)
194
+ df = pd.DataFrame(data, columns=['timestamp', 'short_amount', 'long_amount'])
195
+ df[['short_amount', 'long_amount']] = df[['short_amount', 'long_amount']].astype(float)
196
+ df['timestamp'] = pd.to_datetime(df['timestamp'], unit="s", utc=True)
197
+ df['symbol'] = symbol
198
+ return df
199
+
200
+ async def fetch_hyperliquid_top_positions(self) -> Optional[Any]:
201
+ url = 'https://capi.coinglass.com/api/hyperliquid/topPosition'
202
+ async with self.session.get(url, headers=HEADERS) as response:
203
+ if response.status == 200:
204
+ return await self.dec_data(response)
205
+ print(f"请求失败,状态码: {response.status}: {await response.text()}")
206
+ return None
207
+
208
+ async def fetch_tickers(self) -> Optional[Any]:
209
+ url = 'https://fapi.coinglass.com/api/select/coins/tickers'
210
+ params = {'exName': 'Binance'}
211
+ async with self.session.get(url, params=params, headers=HEADERS) as response:
212
+ if response.status == 200:
213
+ return await self.dec_data(response)
214
+ print(f"请求失败,状态码: {response.status}: {await response.text()}")
215
+ return None
216
+
217
+ async def fetch_symbols(self, only_usdt: bool = True) -> List[str]:
218
+ tickers = await self.fetch_tickers()
219
+ if tickers:
220
+ symbols = [ticker['instrument']['instrumentId'] for ticker in tickers]
221
+ if only_usdt:
222
+ symbols = [symbol for symbol in symbols if symbol.endswith('USDT')]
223
+ return symbols
224
+ return []
225
+
226
+ async def stop(self):
227
+ await self.session.close()
228
+
229
+ # ------------------ 主程序 ------------------
230
+ async def main():
231
+ api = CoinglassApi()
232
+ df = await api.fetch_price_klines('Binance_BTCUSDT', datetime.now() - timedelta(days=1))
233
+ print(df)
234
+ await api.stop()
235
+
236
+ if __name__ == '__main__':
237
+ asyncio.run(main())
@@ -0,0 +1,44 @@
1
+ # import asyncio
2
+ # from datetime import datetime, timedelta
3
+ # from src.hyperquant.core import Exchange
4
+ # from src.hyperquant.datavison.coinglass import CoinglassApi
5
+
6
+
7
+ # async def main():
8
+ # api = CoinglassApi()
9
+ # await api.connect()
10
+ # df = await api.fetch_price_klines('Binance_BTCUSDT', datetime.now() - timedelta(days=1))
11
+ # print(df)
12
+ # await api.stop()
13
+
14
+ # if __name__ == '__main__':
15
+ # asyncio.run(main())
16
+
17
+
18
+ import asyncio
19
+ from datetime import datetime, timedelta
20
+ from hyperquant.datavison.binance import BinanceSwap
21
+
22
+
23
+ if __name__ == "__main__":
24
+ import time
25
+
26
+ async def main():
27
+ symbol = "BTCUSDT"
28
+ interval = "1m"
29
+ # 取最近10分钟的K线
30
+ end_time = int(time.time() * 1000)
31
+ start_time = end_time - 10 * 60 * 1000
32
+ swap = BinanceSwap()
33
+
34
+
35
+ # 新增时间参数例子
36
+ start_date = datetime.now() - timedelta(minutes=5)
37
+ end_date = datetime.now()
38
+ klines = await swap.get_klines(symbol, interval, start_date, end_date)
39
+
40
+ print(klines)
41
+
42
+ await swap.session.close()
43
+
44
+ asyncio.run(main())