openfund-core 0.0.2__tar.gz → 0.0.4__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.
Files changed (57) hide show
  1. {openfund_core-0.0.2 → openfund_core-0.0.4}/PKG-INFO +2 -1
  2. {openfund_core-0.0.2 → openfund_core-0.0.4}/pyproject.toml +4 -5
  3. openfund_core-0.0.4/src/openfund/core/__init__.py +14 -0
  4. openfund_core-0.0.4/src/openfund/core/api_tools/binance_futures_tools.py +23 -0
  5. openfund_core-0.0.4/src/openfund/core/api_tools/binance_tools.py +26 -0
  6. {openfund_core-0.0.2/src/openfund/core/libs → openfund_core-0.0.4/src/openfund/core/api_tools}/enums.py +48 -16
  7. openfund_core-0.0.4/src/openfund/core/base_collector.py +72 -0
  8. openfund_core-0.0.4/src/openfund/core/base_tool.py +58 -0
  9. openfund_core-0.0.4/src/openfund/core/factory.py +97 -0
  10. {openfund_core-0.0.2/src/openfund/core → openfund_core-0.0.4/src/openfund/core/openfund_old}/__init__.py +0 -0
  11. openfund_core-0.0.4/src/openfund/core/pyopenfund.py +85 -0
  12. openfund_core-0.0.4/src/openfund/core/services/um_futures_collector.py +142 -0
  13. openfund_core-0.0.4/src/openfund/core/utils/time_tools.py +25 -0
  14. {openfund_core-0.0.2/src/openfund/core/openfund_old → openfund_core-0.0.4/tests}/__init__.py +0 -0
  15. {openfund_core-0.0.2/tests/binance_tools → openfund_core-0.0.4/tests/api_tools}/test_binance_tools.py +14 -4
  16. openfund_core-0.0.4/tests/api_tools/test_binance_um_futures.py +61 -0
  17. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/conftest.py +0 -14
  18. openfund_core-0.0.4/tests/services/test_um_futures_collector.py +27 -0
  19. openfund_core-0.0.2/src/openfund/core/binance_tools/binance_tools.py +0 -39
  20. openfund_core-0.0.2/src/openfund/core/binance_tools/continuous_klines.py +0 -147
  21. openfund_core-0.0.2/src/openfund/core/factory.py +0 -37
  22. openfund_core-0.0.2/src/openfund/core/libs/__init__.py +0 -6
  23. openfund_core-0.0.2/src/openfund/core/libs/email_tools.py +0 -56
  24. openfund_core-0.0.2/src/openfund/core/libs/file_tools.py +0 -13
  25. openfund_core-0.0.2/src/openfund/core/libs/log_tools.py +0 -45
  26. openfund_core-0.0.2/src/openfund/core/libs/prepare_env.py +0 -28
  27. openfund_core-0.0.2/src/openfund/core/libs/time.py +0 -14
  28. openfund_core-0.0.2/src/openfund/core/libs/time_tools.py +0 -22
  29. openfund_core-0.0.2/src/openfund/core/pyopenfund.py +0 -32
  30. openfund_core-0.0.2/src/openfund/core/sample/__init__.py +0 -1
  31. openfund_core-0.0.2/src/openfund/core/sample/sample.py +0 -20
  32. openfund_core-0.0.2/tests/helpers.py +0 -23
  33. {openfund_core-0.0.2 → openfund_core-0.0.4}/LICENSE +0 -0
  34. {openfund_core-0.0.2 → openfund_core-0.0.4}/README.md +0 -0
  35. {openfund_core-0.0.2/src/openfund/core/binance_tools → openfund_core-0.0.4/src/openfund/core/api_tools}/__init__.py +0 -0
  36. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/continuous_klines.py +0 -0
  37. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/depth.py +0 -0
  38. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/historical_trades.py +0 -0
  39. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/index_info.py +0 -0
  40. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/index_price_kline.py +0 -0
  41. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/klines.py +0 -0
  42. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/klines_qrr.py +0 -0
  43. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/mark_price.py +0 -0
  44. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/mark_price_klines.py +0 -0
  45. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/openfund_old/ticker_24hr_price_change.py +0 -0
  46. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/sycu_exam/__init__.py +0 -0
  47. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/sycu_exam/exam.py +0 -0
  48. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/sycu_exam/random_grade_cplus.py +0 -0
  49. {openfund_core-0.0.2 → openfund_core-0.0.4}/src/openfund/core/sycu_exam/random_grade_web.py +0 -0
  50. {openfund_core-0.0.2/tests → openfund_core-0.0.4/tests/api_tools}/__init__.py +0 -0
  51. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/expected_pyproject.toml +0 -0
  52. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/expected_pyproject_with_exclude.toml +0 -0
  53. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/expected_pyproject_with_latest.toml +0 -0
  54. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/expected_pyproject_with_latest_and_pinned.toml +0 -0
  55. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/expected_pyproject_with_latest_and_preserve_wildcard.toml +0 -0
  56. {openfund_core-0.0.2 → openfund_core-0.0.4}/tests/fixtures/sample_project/pyproject.toml +0 -0
  57. {openfund_core-0.0.2/tests/binance_tools → openfund_core-0.0.4/tests/services}/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openfund-core
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary:
5
5
  Author: yang99love
6
6
  Author-email: yang99love@hotmail.com
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: apscheduler (>=3.10.4,<4.0.0)
15
16
  Requires-Dist: binance-connector (>=3.9.0,<4.0.0)
16
17
  Requires-Dist: binance-futures-connector (>=4.1.0,<5.0.0)
17
18
  Requires-Dist: httpretty (>=1.1.4,<2.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openfund-core"
3
- version = "0.0.2"
3
+ version = "0.0.4"
4
4
  description = ""
5
5
  authors = ["yang99love <yang99love@hotmail.com>"]
6
6
  readme = "README.md"
@@ -11,18 +11,17 @@ include = [
11
11
 
12
12
  [tool.poetry.dependencies] # main dependency group
13
13
  python = "^3.8"
14
- binance-futures-connector = "^4.1.0"
15
- binance-connector = "^3.9.0"
16
14
  poetry = "^1.8.4"
17
15
  httpretty = "^1.1.4"
16
+ apscheduler = "^3.10.4"
17
+ binance-connector = "^3.9.0"
18
+ binance-futures-connector = "^4.1.0"
18
19
 
19
20
  [tool.poetry.group.dev.dependencies]
20
21
  pre-commit = ">=2.15.0"
21
22
  vendoring = ">=1.0"
22
23
 
23
24
  [tool.poetry.group.test.dependencies]
24
- binance-futures-connector = "^4.1.0"
25
- binance-connector = "^3.9.0"
26
25
  httpretty = "^1.1.4"
27
26
  pytest = ">=7.1.2"
28
27
  pytest-cov = ">=3.0.0"
@@ -0,0 +1,14 @@
1
+ # import time
2
+ # from apscheduler.schedulers.blocking import BlockingScheduler
3
+
4
+
5
+ # def taskDetail(taskName: str):
6
+ # currTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
7
+ # print(f"{taskName}-->", "currTime:", currTime)
8
+
9
+
10
+ # if __name__ == "__main__":
11
+ # apSchedule = BlockingScheduler()
12
+ # apSchedule.add_job(func=taskDetail, trigger="interval", seconds=5, args=["task-A"])
13
+
14
+ # apSchedule.start()
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ from openfund.core.base_tool import Tool as BaseTool
6
+ from openfund.core.pyopenfund import Openfund
7
+
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class BinanceUMFuturesTool(BaseTool):
13
+ def __init__(self, openfund: Openfund | None = None) -> None:
14
+ super().__init__(openfund, "binance")
15
+
16
+ def time(self):
17
+ return self.umclient.time()
18
+
19
+ def ping(self):
20
+ return self.umclient.ping()
21
+
22
+ def klines(self, symbol: str, interval: str = "1m", **kwargs):
23
+ return self.umclient.klines(symbol=symbol, interval=interval, **kwargs)
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from poetry.utils.authenticator import Authenticator
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ from openfund.core.base_tool import Tool as BaseTool
9
+ from openfund.core.pyopenfund import Openfund
10
+
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class BinanceTools(BaseTool):
16
+ def __init__(self, openfund: Openfund | None = None) -> None:
17
+ super().__init__(openfund, "binance")
18
+
19
+ def get_time(self):
20
+ return self.client.time()
21
+
22
+ def get_account(self):
23
+ return self.client.account()
24
+
25
+ def get_klines(self, symbol: str, interval: str, **kwargs):
26
+ return self.client.klines(symbol=symbol, interval=interval, **kwargs)
@@ -10,22 +10,54 @@ ORDER_STATUS_PENDING_CANCEL = "PENDING_CANCEL"
10
10
  ORDER_STATUS_REJECTED = "REJECTED"
11
11
  ORDER_STATUS_EXPIRED = "EXPIRED"
12
12
 
13
- KLINE_INTERVAL_1SECOND = "1s"
14
- KLINE_INTERVAL_1MINUTE = "1m"
15
- KLINE_INTERVAL_3MINUTE = "3m"
16
- KLINE_INTERVAL_5MINUTE = "5m"
17
- KLINE_INTERVAL_15MINUTE = "15m"
18
- KLINE_INTERVAL_30MINUTE = "30m"
19
- KLINE_INTERVAL_1HOUR = "1h"
20
- KLINE_INTERVAL_2HOUR = "2h"
21
- KLINE_INTERVAL_4HOUR = "4h"
22
- KLINE_INTERVAL_6HOUR = "6h"
23
- KLINE_INTERVAL_8HOUR = "8h"
24
- KLINE_INTERVAL_12HOUR = "12h"
25
- KLINE_INTERVAL_1DAY = "1d"
26
- KLINE_INTERVAL_3DAY = "3d"
27
- KLINE_INTERVAL_1WEEK = "1w"
28
- KLINE_INTERVAL_1MONTH = "1M"
13
+
14
+ class KlineInterval(Enum):
15
+ KLINE_INTERVAL_1SECOND = ("1s", 1, "s")
16
+ KLINE_INTERVAL_1MINUTE = ("1m", 1, "m")
17
+ KLINE_INTERVAL_3MINUTE = ("3m", 3, "m")
18
+ KLINE_INTERVAL_5MINUTE = ("5m", 5, "m")
19
+ KLINE_INTERVAL_15MINUTE = ("15m", 15, "m")
20
+ KLINE_INTERVAL_30MINUTE = ("30m", 30, "m")
21
+ KLINE_INTERVAL_1HOUR = ("1h", 1, "h")
22
+ KLINE_INTERVAL_2HOUR = ("2h", 2, "h")
23
+ KLINE_INTERVAL_4HOUR = ("4h", 4, "h")
24
+ KLINE_INTERVAL_6HOUR = ("6h", 6, "h")
25
+ KLINE_INTERVAL_8HOUR = ("8h", 8, "h")
26
+ KLINE_INTERVAL_12HOUR = ("12h", 12, "h")
27
+ KLINE_INTERVAL_1DAY = ("1d", 1, "d")
28
+ KLINE_INTERVAL_3DAY = ("3d", 3, "d")
29
+ KLINE_INTERVAL_1WEEK = ("1w", 1, "d")
30
+ KLINE_INTERVAL_1MONTH = ("1M", 1, "M")
31
+
32
+ def __init__(self, value: str, unit: int, unitType: str):
33
+ self._value_ = value
34
+ self.unit = unit
35
+ self.unitType = unitType
36
+
37
+ @classmethod
38
+ def getByUnit(cls, unit: int, unitType: str) -> str:
39
+ for interval in KlineInterval:
40
+ if interval.unit == unit and interval.unitType == unitType:
41
+ return interval.value
42
+ return None
43
+
44
+
45
+ # KLINE_INTERVAL_1SECOND = "1s"
46
+ # KLINE_INTERVAL_1MINUTE = "1m"
47
+ # KLINE_INTERVAL_3MINUTE = "3m"
48
+ # KLINE_INTERVAL_5MINUTE = "5m"
49
+ # KLINE_INTERVAL_15MINUTE = "15m"
50
+ # KLINE_INTERVAL_30MINUTE = "30m"
51
+ # KLINE_INTERVAL_1HOUR = "1h"
52
+ # KLINE_INTERVAL_2HOUR = "2h"
53
+ # KLINE_INTERVAL_4HOUR = "4h"
54
+ # KLINE_INTERVAL_6HOUR = "6h"
55
+ # KLINE_INTERVAL_8HOUR = "8h"
56
+ # KLINE_INTERVAL_12HOUR = "12h"
57
+ # KLINE_INTERVAL_1DAY = "1d"
58
+ # KLINE_INTERVAL_3DAY = "3d"
59
+ # KLINE_INTERVAL_1WEEK = "1w"
60
+ # KLINE_INTERVAL_1MONTH = "1M"
29
61
 
30
62
  SIDE_BUY = "BUY"
31
63
  SIDE_SELL = "SELL"
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import csv
5
+
6
+ from abc import abstractmethod
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING
9
+
10
+ from apscheduler.job import Job
11
+
12
+ from openfund.core.pyopenfund import Openfund
13
+ from openfund.core.factory import Factory
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class Collector:
20
+ def __init__(self, openfund: Openfund | None = None) -> None:
21
+ self._openfund: Openfund = openfund
22
+ if self._openfund is None:
23
+ self._openfund = Factory.create_openfund()
24
+ self._job: Job = None
25
+
26
+ @property
27
+ def openfund(self) -> Openfund:
28
+ return self._openfund
29
+
30
+ @abstractmethod
31
+ def collect(self) -> None:
32
+ raise NotImplementedError()
33
+
34
+ @abstractmethod
35
+ def start(self) -> int:
36
+ raise NotImplementedError()
37
+ # from apscheduler.schedulers.background import BlockingScheduler
38
+
39
+ # apSchedule = BlockingScheduler()
40
+ # self.openfund.scheduler.add_job(
41
+ # func=self.collect, trigger="interval", minutes=5,seconds=5 id="um_futures_collector"
42
+ # )
43
+
44
+ def stop(self) -> int:
45
+ if self._job is not None:
46
+ self._job.remove()
47
+ logger.debug(f"{self._job.name} is stop .")
48
+ return 0
49
+
50
+ def pause(self) -> int:
51
+ if self._job is not None:
52
+ self._job.pause()
53
+ logger.debug(f"{self._job.name} is pause .")
54
+ return 0
55
+
56
+ def resume(self) -> int:
57
+ if self._job is not None:
58
+ self._job.resume()
59
+ logger.debug(f"{self._job.name} is resume .")
60
+ return 0
61
+
62
+ def _write_to_csv(self, file: Path, listData: list) -> None:
63
+
64
+ # 如果路径不存在,创建路径
65
+ file.parent.mkdir(parents=True, exist_ok=True)
66
+
67
+ with open(file, "a", newline="") as file:
68
+ writer = csv.writer(file)
69
+ # 时间戳倒序,插入文件尾部
70
+ writer.writerows(sorted(listData, key=lambda x: x[0], reverse=True))
71
+
72
+ logger.debug("2、{}条写入{}文件...".format(len(listData), file))
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ from pathlib import Path
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ from poetry.utils.authenticator import Authenticator
10
+ from binance.spot import Spot as Client
11
+ from binance.um_futures import UMFutures as UMClient
12
+
13
+ from openfund.core.pyopenfund import Openfund
14
+ from openfund.core.factory import Factory
15
+
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class Tool:
21
+ def __init__(
22
+ self, openfund: Openfund | None = None, toolname: str = "binance"
23
+ ) -> None:
24
+ self._openfund: Openfund = openfund
25
+ if self._openfund is None:
26
+ self._openfund = Factory.create_openfund()
27
+
28
+ self._toolname = toolname
29
+ self._password_manager = Authenticator(
30
+ self._openfund._poetry.config
31
+ )._password_manager
32
+
33
+ self._client = None
34
+ self._umclient = None
35
+
36
+ @property
37
+ def api_key(self) -> str:
38
+ return self._password_manager.get_http_auth(self._toolname).get("username")
39
+
40
+ @property
41
+ def apk_secret(self) -> str:
42
+ return self._password_manager.get_http_auth(self._toolname).get("password")
43
+
44
+ @property
45
+ def openfund(self) -> Openfund:
46
+ return self._openfund
47
+
48
+ @property
49
+ def client(self) -> Client:
50
+ if self._client is None:
51
+ self._client = Client(self.api_key, self.apk_secret)
52
+ return self._client
53
+
54
+ @property
55
+ def umclient(self) -> UMClient:
56
+ if self._umclient is None:
57
+ self._umclient = UMClient(self.api_key, self.apk_secret)
58
+ return self._umclient
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ from poetry.factory import Factory as BaseFactory
9
+ from openfund.core.pyopenfund import Openfund
10
+
11
+
12
+ if TYPE_CHECKING:
13
+ from poetry.poetry import Poetry
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+ _APP_NAME = "pyopenfund"
18
+
19
+
20
+ class Factory(BaseFactory):
21
+ _openfund: Openfund = None
22
+
23
+ def __init__(self) -> None:
24
+ super().__init__()
25
+ self._init_log()
26
+
27
+ def create_poetry(
28
+ self,
29
+ cwd: Path | None = None,
30
+ with_groups: bool = True,
31
+ ) -> Poetry:
32
+ poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)
33
+ return poetry
34
+
35
+ @classmethod
36
+ def create_openfund(
37
+ cls,
38
+ cwd: Path | None = None,
39
+ with_groups: bool = True,
40
+ ) -> Openfund:
41
+ if cls._openfund is not None:
42
+ return cls._openfund
43
+
44
+ if cwd is None:
45
+ cwd = Path.cwd()
46
+
47
+ poetry = Factory().create_poetry(cwd=cwd, with_groups=with_groups)
48
+ cls._openfund = Openfund(poetry)
49
+ cls._openfund.scheduler.start()
50
+ return cls._openfund
51
+
52
+ def _init_log(self):
53
+ from openfund.core.pyopenfund import user_log_path
54
+
55
+ log_file = user_log_path(
56
+ _APP_NAME, appauthor=False, ensure_exists=True
57
+ ).resolve()
58
+ log_file = (
59
+ user_log_path(_APP_NAME, appauthor=False, ensure_exists=True)
60
+ .joinpath("openfund-core.log")
61
+ .resolve()
62
+ )
63
+ fileHandler = FileHandler(log_file)
64
+ fileHandler.setFormatter(FileFormatter())
65
+ console_handler = logging.StreamHandler()
66
+ console_handler.setFormatter(FileFormatter())
67
+ logging.basicConfig(
68
+ level=logging.DEBUG,
69
+ handlers=[console_handler, fileHandler],
70
+ )
71
+
72
+
73
+ from logging.handlers import TimedRotatingFileHandler
74
+
75
+
76
+ class FileHandler(TimedRotatingFileHandler):
77
+ def __init__(
78
+ self,
79
+ filename,
80
+ when="midnight",
81
+ interval=1,
82
+ backupCount=7,
83
+ encoding=None,
84
+ delay=False,
85
+ utc=False,
86
+ ) -> None:
87
+ super().__init__(filename, when, interval, backupCount, encoding, delay, utc)
88
+
89
+
90
+ class FileFormatter(logging.Formatter):
91
+
92
+ _format = "%(asctime)s - %(process)d | %(threadName)s | %(module)s.%(funcName)s:%(lineno)d - %(levelname)s -%(message)s"
93
+
94
+ _datefmt = "%Y-%m-%d-%H:%M:%S" # 时间
95
+
96
+ def __init__(self, fmt=_format, datefmt=_datefmt, style="%") -> None:
97
+ super().__init__(fmt, datefmt, style)
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ import sys
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ from pathlib import Path
10
+
11
+ from platformdirs import user_cache_path
12
+ from platformdirs import user_config_path
13
+ from platformdirs import user_data_path
14
+ from platformdirs import user_log_path
15
+ from apscheduler.schedulers.background import BackgroundScheduler
16
+
17
+ if TYPE_CHECKING:
18
+ from poetry.poetry import Poetry
19
+ from openfund.core.factory import Factory
20
+
21
+ logger = logging.getLogger(__name__)
22
+ _APP_NAME = "pyopenfund"
23
+
24
+
25
+ class Openfund:
26
+ def __init__(self, poetry: Openfund) -> None:
27
+ self._poetry: Poetry = poetry
28
+ self._schedule: BackgroundScheduler = None
29
+
30
+ @property
31
+ def poetry(self) -> Poetry:
32
+ from pathlib import Path
33
+
34
+ if self._poetry is not None:
35
+ return self._poetry
36
+
37
+ project_path = Path.cwd()
38
+
39
+ self._poetry = Factory().create_poetry(
40
+ cwd=project_path,
41
+ )
42
+
43
+ return self._poetry
44
+
45
+ @property
46
+ def dataDir(self) -> Path:
47
+ # openfund_home = os.getenv("OPENFUND_HOME")
48
+ # if openfund_home:
49
+ # return Path(openfund_home).expanduser()
50
+ return Path(
51
+ os.getenv("OPENFUND_DATA_DIR")
52
+ or user_data_path(_APP_NAME, appauthor=False, roaming=True)
53
+ ).joinpath("data")
54
+
55
+ @property
56
+ def cacheDir(self) -> Path:
57
+ return Path(
58
+ os.getenv("OPENFUND_CACHE_DIR")
59
+ or user_cache_path(_APP_NAME, appauthor=False)
60
+ )
61
+
62
+ @property
63
+ def configDir(self) -> Path:
64
+
65
+ return Path(
66
+ os.getenv("OPENFUND_CONFIG_DIR")
67
+ or user_config_path(_APP_NAME, appauthor=False, roaming=True)
68
+ ).joinpath("config")
69
+
70
+ @property
71
+ def logDir(self) -> Path:
72
+
73
+ return Path(
74
+ os.getenv("OPENFUND_LOG_DIR")
75
+ or user_log_path(_APP_NAME, appauthor=False, roaming=True)
76
+ )
77
+
78
+ @property
79
+ def scheduler(self) -> BackgroundScheduler:
80
+ if self._schedule is None:
81
+ self._schedule = BackgroundScheduler(
82
+ timezone="MST",
83
+ )
84
+
85
+ return self._schedule
@@ -0,0 +1,142 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ import logging
5
+ import time
6
+ from pathlib import Path
7
+
8
+ from openfund.core.api_tools.enums import KlineInterval
9
+ from openfund.core.base_tool import Tool as BaseTool
10
+ from openfund.core.api_tools.binance_futures_tools import BinanceUMFuturesTool
11
+ from openfund.core.base_collector import Collector as BaseCollector
12
+
13
+ from openfund.core.utils.time_tools import TimeTools
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class KLinesCollector(BaseCollector):
19
+ def __init__(
20
+ self,
21
+ hisSwitch: int = 0,
22
+ hisDateTime: int = 0,
23
+ pool: list = None,
24
+ interval: int = 5,
25
+ client: BaseTool = None,
26
+ ) -> None:
27
+ super().__init__()
28
+ self._pool = pool
29
+ if self._pool is None:
30
+ self._pool = ["BTCUSDT", "ETHUSDT"]
31
+ logger.debug("+++++++++++++++ KLinesCollector init +++++++++++++ ")
32
+
33
+ self._interval = interval
34
+ self._hisSwitch = hisSwitch
35
+ self._hisDateTime = hisDateTime
36
+ self._dataDir = self.openfund.dataDir
37
+ self._client = client
38
+ if self._client is None:
39
+ self._client = BinanceUMFuturesTool().umclient
40
+ # self._job = None
41
+
42
+ def collect(self) -> None:
43
+
44
+ for symbol in self._pool:
45
+ logger.debug("{} symbol 开始 ++++++++++++++++++++++++++++ ".format(symbol))
46
+ latestRecords = 1 # 采集最近一次的记录数量
47
+ records = 0 # 累计记录数
48
+ queryCount = 0 # 执行次数
49
+ nextEndTime = 0
50
+ params = {"limit": 1000}
51
+ while latestRecords != 0: # 循环读取,直到记录为空
52
+ queryCount += 1
53
+ if nextEndTime != 0:
54
+ params = {"limit": 1000, "endTime": nextEndTime}
55
+
56
+ logger.debug("1、{}第{}次开始执行...".format(symbol, queryCount))
57
+ listData = []
58
+ try:
59
+ listData = self._client.klines(
60
+ symbol,
61
+ KlineInterval.getByUnit(self._interval, "m"),
62
+ **params,
63
+ )
64
+ except Exception as e:
65
+ # print("Error:", e)
66
+ logger.error(e)
67
+ time.sleep(10)
68
+ continue
69
+
70
+ latestRecords = len(listData)
71
+ data_file = Path(
72
+ self._dataDir.joinpath("klines")
73
+ .joinpath(symbol)
74
+ .joinpath(
75
+ "klines_{}.csv".format(
76
+ KlineInterval.getByUnit(self._interval, "m")
77
+ )
78
+ )
79
+ )
80
+ self._write_to_csv(data_file, listData)
81
+
82
+ if latestRecords > 0:
83
+ nextEndTime = (
84
+ # -1 不和close时间戳相同,避免重新拉取重复数据
85
+ listData[0][0]
86
+ - 1
87
+ )
88
+
89
+ logger.debug(
90
+ "3、下次结束时间 %s %s"
91
+ % (TimeTools.format_timestamp(nextEndTime), nextEndTime)
92
+ )
93
+
94
+ if self._hisSwitch == 0 or nextEndTime <= self._hisDateTime:
95
+ break
96
+ else:
97
+ logger.debug("4、结束...")
98
+
99
+ # time.sleep(0.1)
100
+ records = latestRecords + records
101
+ logger.info("5、{} 抓取数据 {} 条记录...".format(symbol, records))
102
+ logger.debug("{} symbol --------------------------------- ".format(symbol))
103
+
104
+ # def taskDetail(taskName: str):
105
+ # currTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
106
+ # logger.debug(f"{taskName}-->", "currTime:", currTime)
107
+
108
+ def start(self) -> int:
109
+
110
+ # self.collect()
111
+ self._job = self.openfund.scheduler.add_job(
112
+ func=self.collect,
113
+ trigger="interval",
114
+ # minutes=self._interval,
115
+ seconds=self._interval,
116
+ id="um_futures_collector",
117
+ )
118
+
119
+ logger.debug("调度任务已启动,每%s分钟执行一次。", self._interval)
120
+
121
+ return 0
122
+
123
+
124
+ # if __name__ == "__main__":
125
+ # from openfund.core.services.um_futures_collector import KLinesCollector
126
+
127
+ # collector = KLinesCollector()
128
+
129
+ # collector.start()
130
+ # logger.debug(f"main collector.start() ===== ")
131
+ # i = 0
132
+ # while i < 10:
133
+
134
+ # logger.debug("main i=%s ===== ", i)
135
+ # if i == 2:
136
+ # collector.pause()
137
+ # if i == 4:
138
+ # collector.resume()
139
+ # if i == 8:
140
+ # collector.stop()
141
+ # time.sleep(5)
142
+ # i += 1
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env python
2
+
3
+ import time
4
+ from datetime import date, datetime, timedelta
5
+
6
+
7
+ class TimeTools:
8
+
9
+ @staticmethod
10
+ def print_timestamp(timestamp):
11
+ print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp / 1000)))
12
+
13
+ @staticmethod
14
+ def format_timestamp(timestamp):
15
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp / 1000))
16
+
17
+ @staticmethod
18
+ def format_date(timestamp):
19
+ return time.strftime("%Y-%m-%d", time.localtime(timestamp / 1000))
20
+
21
+ @staticmethod
22
+ def format_date_to(to_days):
23
+ now = date.today()
24
+ to = now + timedelta(days=to_days)
25
+ return to