openfund-core 0.0.2__py3-none-any.whl → 0.0.4__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.
- openfund/core/__init__.py +14 -0
- openfund/core/api_tools/binance_futures_tools.py +23 -0
- openfund/core/api_tools/binance_tools.py +26 -0
- openfund/core/{libs → api_tools}/enums.py +48 -16
- openfund/core/base_collector.py +72 -0
- openfund/core/base_tool.py +58 -0
- openfund/core/factory.py +63 -3
- openfund/core/pyopenfund.py +56 -3
- openfund/core/services/um_futures_collector.py +142 -0
- openfund/core/utils/time_tools.py +25 -0
- {openfund_core-0.0.2.dist-info → openfund_core-0.0.4.dist-info}/METADATA +2 -1
- openfund_core-0.0.4.dist-info/RECORD +30 -0
- openfund/core/binance_tools/binance_tools.py +0 -39
- openfund/core/binance_tools/continuous_klines.py +0 -147
- openfund/core/libs/__init__.py +0 -6
- openfund/core/libs/email_tools.py +0 -56
- openfund/core/libs/file_tools.py +0 -13
- openfund/core/libs/log_tools.py +0 -45
- openfund/core/libs/prepare_env.py +0 -28
- openfund/core/libs/time.py +0 -14
- openfund/core/libs/time_tools.py +0 -22
- openfund/core/sample/__init__.py +0 -1
- openfund/core/sample/sample.py +0 -20
- openfund_core-0.0.2.dist-info/RECORD +0 -35
- /openfund/core/{binance_tools → api_tools}/__init__.py +0 -0
- {openfund_core-0.0.2.dist-info → openfund_core-0.0.4.dist-info}/LICENSE +0 -0
- {openfund_core-0.0.2.dist-info → openfund_core-0.0.4.dist-info}/WHEEL +0 -0
openfund/core/__init__.py
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
openfund/core/factory.py
CHANGED
@@ -4,19 +4,25 @@ import logging
|
|
4
4
|
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import TYPE_CHECKING
|
7
|
+
|
7
8
|
from poetry.factory import Factory as BaseFactory
|
8
9
|
from openfund.core.pyopenfund import Openfund
|
9
10
|
|
11
|
+
|
10
12
|
if TYPE_CHECKING:
|
11
13
|
from poetry.poetry import Poetry
|
12
14
|
|
13
15
|
|
14
16
|
logger = logging.getLogger(__name__)
|
17
|
+
_APP_NAME = "pyopenfund"
|
15
18
|
|
16
19
|
|
17
20
|
class Factory(BaseFactory):
|
21
|
+
_openfund: Openfund = None
|
22
|
+
|
18
23
|
def __init__(self) -> None:
|
19
24
|
super().__init__()
|
25
|
+
self._init_log()
|
20
26
|
|
21
27
|
def create_poetry(
|
22
28
|
self,
|
@@ -26,12 +32,66 @@ class Factory(BaseFactory):
|
|
26
32
|
poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)
|
27
33
|
return poetry
|
28
34
|
|
35
|
+
@classmethod
|
29
36
|
def create_openfund(
|
30
|
-
|
37
|
+
cls,
|
31
38
|
cwd: Path | None = None,
|
32
39
|
with_groups: bool = True,
|
33
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"
|
34
93
|
|
35
|
-
|
94
|
+
_datefmt = "%Y-%m-%d-%H:%M:%S" # 时间
|
36
95
|
|
37
|
-
|
96
|
+
def __init__(self, fmt=_format, datefmt=_datefmt, style="%") -> None:
|
97
|
+
super().__init__(fmt, datefmt, style)
|
openfund/core/pyopenfund.py
CHANGED
@@ -1,20 +1,31 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import logging
|
4
|
+
import os
|
5
|
+
import sys
|
6
|
+
|
3
7
|
from typing import TYPE_CHECKING
|
4
|
-
from typing import Any
|
5
8
|
|
6
|
-
from
|
9
|
+
from pathlib import Path
|
7
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
|
8
16
|
|
9
17
|
if TYPE_CHECKING:
|
10
|
-
from poetry.core.packages.project_package import ProjectPackage
|
11
18
|
from poetry.poetry import Poetry
|
12
19
|
from openfund.core.factory import Factory
|
13
20
|
|
21
|
+
logger = logging.getLogger(__name__)
|
22
|
+
_APP_NAME = "pyopenfund"
|
23
|
+
|
14
24
|
|
15
25
|
class Openfund:
|
16
26
|
def __init__(self, poetry: Openfund) -> None:
|
17
27
|
self._poetry: Poetry = poetry
|
28
|
+
self._schedule: BackgroundScheduler = None
|
18
29
|
|
19
30
|
@property
|
20
31
|
def poetry(self) -> Poetry:
|
@@ -30,3 +41,45 @@ class Openfund:
|
|
30
41
|
)
|
31
42
|
|
32
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: openfund-core
|
3
|
-
Version: 0.0.
|
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)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
openfund/core/__init__.py,sha256=EHcPx-8t19Rp43en5LclC-v-VuRK3CFRrh5rCA8h0w0,422
|
2
|
+
openfund/core/api_tools/__init__.py,sha256=paV2IWM0QkD0ddq0UWdbsDeQTW3OBAPjMf51V5yMRgI,458
|
3
|
+
openfund/core/api_tools/binance_futures_tools.py,sha256=T2WLpVmtnK9FwWlaoXrzmejJoYheQjmx51gc7_tolO8,604
|
4
|
+
openfund/core/api_tools/binance_tools.py,sha256=B5Dwblu04VSY8ppVO1a_a7NumqLEsiZ6FKIh03WD1AI,688
|
5
|
+
openfund/core/api_tools/enums.py,sha256=HXtX8Qz62q7SHsn2URxKWIoeZvVimsLrhMzN_-uBDgQ,10050
|
6
|
+
openfund/core/base_collector.py,sha256=x-ELr-lR34Q2zJO2cD2h5tZFaTl93z46jwOLvBKkckc,2049
|
7
|
+
openfund/core/base_tool.py,sha256=wq5b4-Rz_SITPp09UfOwBXXaMB82nJgdamHkGndYKwM,1553
|
8
|
+
openfund/core/factory.py,sha256=Skjy6Br8k45H7_D2S5wKW0uqzY_S6Fmkddr1ErgnYiI,2557
|
9
|
+
openfund/core/openfund_old/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
openfund/core/openfund_old/continuous_klines.py,sha256=KaGW4bo88RVEg0e_Cvpg8nvQD8qkGt4k_yLvtvzFCeU,4954
|
11
|
+
openfund/core/openfund_old/depth.py,sha256=L6yejSRpd37fmAk7Qowaxw1ELPwDGxKE0JCtlkJ00YE,2682
|
12
|
+
openfund/core/openfund_old/historical_trades.py,sha256=JhvhyDp4CVG1gRhlKBaa01DWGWRHnMO3AV_PORTkkIw,4243
|
13
|
+
openfund/core/openfund_old/index_info.py,sha256=idJCW5vvVZpMjmlXpu24emRC8MH2dcEUZq2YnaDB1q4,1766
|
14
|
+
openfund/core/openfund_old/index_price_kline.py,sha256=rAqG3HGZT4SzSPAN_Hk3GLSt-oh_-Fc4h4n9W4iQKKE,3952
|
15
|
+
openfund/core/openfund_old/klines.py,sha256=O_NtJD53HTJL3CTXkV5TrhAe2WBbcVhKA-3sCLaCJY8,3136
|
16
|
+
openfund/core/openfund_old/klines_qrr.py,sha256=OK2SQuUpAb6PCOP8H-60kQE23nM9dB91pDlduH_AowE,3230
|
17
|
+
openfund/core/openfund_old/mark_price.py,sha256=wjLx4Vw_S6Ee1-yIwsOKkiX1R6iaebQAuteQibJAhR8,3535
|
18
|
+
openfund/core/openfund_old/mark_price_klines.py,sha256=FfQW3oh-XM2eR2dV5HAgJYu66ZPdWMVPVgbqe0-kc-c,4017
|
19
|
+
openfund/core/openfund_old/ticker_24hr_price_change.py,sha256=SDv68uPN1OGTN_Dukl3AK7awE1nZuxxho-1PckhZptk,2607
|
20
|
+
openfund/core/pyopenfund.py,sha256=SfcDCFs_YgrJfg00AbNtFZuGkOncvSEUXj8ghfCz4Ww,2144
|
21
|
+
openfund/core/services/um_futures_collector.py,sha256=StyI1Ml-GQmUJHYPcx6klJxs9KUPgFg6tAkJiuhd-rI,4717
|
22
|
+
openfund/core/sycu_exam/__init__.py,sha256=uLZK-YxXqXfAtTTekgfnfqRIdVedM9SBHnmGD3j5sYM,20
|
23
|
+
openfund/core/sycu_exam/exam.py,sha256=x7E3r6DgTMnlUz9q6fVysCPSabp-pQUqhGKw0xRpFrU,395
|
24
|
+
openfund/core/sycu_exam/random_grade_cplus.py,sha256=8FIUnF4ys-at2tAtg0yYXru_mmxhs20ywG5DY9TiHWo,9487
|
25
|
+
openfund/core/sycu_exam/random_grade_web.py,sha256=A2x9-jFx6L_AKAmWGrIrKcc9httJHTA5i0Uc8nGiPTE,8572
|
26
|
+
openfund/core/utils/time_tools.py,sha256=_orqX684epJyh5_xV94JbpQPprIpiuiS__scLeiXr6I,646
|
27
|
+
openfund_core-0.0.4.dist-info/LICENSE,sha256=xazLvYVG6Uw0rtJK_miaYXYn0Y7tWmxIJ35I21fCOFE,11356
|
28
|
+
openfund_core-0.0.4.dist-info/METADATA,sha256=bzyD31o_lS5iN-FOBEIblwEAV0D6k6Pq7ViC8L08ciU,3205
|
29
|
+
openfund_core-0.0.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
30
|
+
openfund_core-0.0.4.dist-info/RECORD,,
|
@@ -1,39 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from poetry.utils.authenticator import Authenticator
|
5
|
-
|
6
|
-
from typing import TYPE_CHECKING
|
7
|
-
from binance.spot import Spot as Client
|
8
|
-
from openfund.core.pyopenfund import Openfund
|
9
|
-
|
10
|
-
|
11
|
-
tools = "binance"
|
12
|
-
logger = logging.getLogger(__name__)
|
13
|
-
|
14
|
-
|
15
|
-
class BinanceTools:
|
16
|
-
def __init__(self, openfund: Openfund) -> None:
|
17
|
-
logger.debug("######## BinanceTools init ########")
|
18
|
-
self._openfund: Openfund = openfund
|
19
|
-
self._password_manager = Authenticator(
|
20
|
-
self._openfund._poetry.config
|
21
|
-
)._password_manager
|
22
|
-
|
23
|
-
@property
|
24
|
-
def api_key(self) -> str:
|
25
|
-
return self._password_manager.get_http_auth(tools).get("username")
|
26
|
-
|
27
|
-
@property
|
28
|
-
def apk_secret(self) -> str:
|
29
|
-
return self._password_manager.get_http_auth(tools).get("password")
|
30
|
-
|
31
|
-
def get_time():
|
32
|
-
client = Client()
|
33
|
-
return client.time()
|
34
|
-
|
35
|
-
def get_account(self):
|
36
|
-
logger.debug("######## BinanceTools.get_account() ########")
|
37
|
-
logger.debug("######## BinanceTools api_key=%s ########", self.api_key)
|
38
|
-
client = Client(self.api_key, self.apk_secret)
|
39
|
-
return client.account()
|
@@ -1,147 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
import csv
|
3
|
-
import logging
|
4
|
-
import time
|
5
|
-
|
6
|
-
from datetime import datetime
|
7
|
-
|
8
|
-
from binance.um_futures import UMFutures
|
9
|
-
from binance.um_futures import UMFutures
|
10
|
-
from binance.error import ClientError
|
11
|
-
|
12
|
-
from libs.time_tools import format_timestamp
|
13
|
-
from libs.file_tools import create_path
|
14
|
-
from libs.prepare_env import get_api_key, get_path
|
15
|
-
from libs import enums
|
16
|
-
|
17
|
-
# 数据路径、日志路径
|
18
|
-
data_path, log_path = get_path()
|
19
|
-
# client
|
20
|
-
um_futures_client = UMFutures()
|
21
|
-
# 合同类型
|
22
|
-
contractTypes = [type.value for type in enums.ContractType]
|
23
|
-
# 币种类型
|
24
|
-
# POOL = enums.CUR_SYMBOL_POOL
|
25
|
-
POOL = [
|
26
|
-
"BTCUSDT_240329",
|
27
|
-
"BLURUSDT",
|
28
|
-
"DYDXUSDT",
|
29
|
-
"ETHBTC",
|
30
|
-
"ETHBUSD",
|
31
|
-
"ETHUSDT",
|
32
|
-
"ETHUSDT_231229",
|
33
|
-
"ETHUSDT_240329",
|
34
|
-
"GMTBUSD",
|
35
|
-
"GMTUSDT",
|
36
|
-
"LTCBUSD",
|
37
|
-
"LTCUSDT",
|
38
|
-
"MATICBUSD",
|
39
|
-
"MATICUSDT",
|
40
|
-
"SOLBUSD",
|
41
|
-
"SOLUSDT",
|
42
|
-
]
|
43
|
-
interval = enums.KLINE_INTERVAL_5MINUTE
|
44
|
-
limit = 1500
|
45
|
-
errorLimit = 100
|
46
|
-
sleepSec = 10
|
47
|
-
|
48
|
-
# 历史截止数据开关
|
49
|
-
hisSwitch = 0
|
50
|
-
# hisSwitch 打开的情况下,抓取数据截止时间
|
51
|
-
hisDateTime = 1653974399999
|
52
|
-
|
53
|
-
for symbol in POOL:
|
54
|
-
fileName = "{}/continuous_klines_{}_{}.log".format(
|
55
|
-
log_path, symbol, format_timestamp(datetime.now().timestamp() * 1000)
|
56
|
-
)
|
57
|
-
# print(fileName)
|
58
|
-
logging.basicConfig(
|
59
|
-
format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
|
60
|
-
datefmt="%Y-%m-%d %H:%M:%S",
|
61
|
-
level=logging.INFO,
|
62
|
-
filename=fileName,
|
63
|
-
)
|
64
|
-
logging.info("{} symbol 开始 ++++++++++++++++++++++++++++ ".format(symbol))
|
65
|
-
total = 0
|
66
|
-
for contractType in contractTypes:
|
67
|
-
latestRecords = 1
|
68
|
-
records = 0 # 累计记录数
|
69
|
-
queryTimes = 0 # 执行次数
|
70
|
-
nextEndTime = 0
|
71
|
-
errorCount = 0
|
72
|
-
params = {"limit": limit}
|
73
|
-
while latestRecords != 0: # 循环读取,直到记录为空
|
74
|
-
queryTimes = queryTimes + 1
|
75
|
-
if nextEndTime != 0:
|
76
|
-
params = {"limit": limit, "endTime": nextEndTime}
|
77
|
-
|
78
|
-
logging.info(
|
79
|
-
"1、{}-{} 第{}次开始执行...".format(symbol, contractType, queryTimes)
|
80
|
-
)
|
81
|
-
listData = []
|
82
|
-
try:
|
83
|
-
listData = um_futures_client.continuous_klines(
|
84
|
-
symbol, contractType, interval, **params
|
85
|
-
)
|
86
|
-
except KeyError as err:
|
87
|
-
print("KeyError:", err)
|
88
|
-
logging.error(err)
|
89
|
-
break
|
90
|
-
except ClientError as error:
|
91
|
-
logging.error(
|
92
|
-
"Found error. status: {}, error code: {}, error message: {}".format(
|
93
|
-
error.status_code, error.error_code, error.error_message
|
94
|
-
)
|
95
|
-
)
|
96
|
-
if error.error_code == -4144 and error.status_code == 400:
|
97
|
-
break
|
98
|
-
except Exception as e:
|
99
|
-
print("Error:", e)
|
100
|
-
logging.error(e)
|
101
|
-
errorCount = errorCount + 1
|
102
|
-
if errorCount > errorLimit:
|
103
|
-
break
|
104
|
-
else:
|
105
|
-
time.sleep(sleepSec)
|
106
|
-
continue
|
107
|
-
|
108
|
-
latestRecords = len(listData)
|
109
|
-
records = latestRecords + records
|
110
|
-
logging.info("2、{}条写入文件...".format(latestRecords))
|
111
|
-
|
112
|
-
path = "{}/continuous_klines/{}/{}/".format(data_path, symbol, contractType)
|
113
|
-
create_path(path) # 不存在路径进行呢创建
|
114
|
-
|
115
|
-
with open(
|
116
|
-
"{}continuous_klines_{}_{}_{}.csv".format(
|
117
|
-
path, symbol, contractType, interval
|
118
|
-
),
|
119
|
-
"a",
|
120
|
-
newline="",
|
121
|
-
) as file:
|
122
|
-
writer = csv.writer(file)
|
123
|
-
# 时间戳倒序,插入文件尾部
|
124
|
-
writer.writerows(sorted(listData, key=lambda x: x[0], reverse=True))
|
125
|
-
|
126
|
-
# 拿到最后一条记录后,获取close时间戳,变为下一次截止时间戳
|
127
|
-
if latestRecords > 0:
|
128
|
-
nextEndTime = (
|
129
|
-
listData[0][0] - 1
|
130
|
-
) # -1 不和close时间戳相同,避免重新拉取重复数据
|
131
|
-
errorCount = 0
|
132
|
-
logging.info(
|
133
|
-
"3、下次结束时间 {} {}".format(
|
134
|
-
format_timestamp(nextEndTime), nextEndTime
|
135
|
-
)
|
136
|
-
)
|
137
|
-
|
138
|
-
if nextEndTime <= hisDateTime and hisSwitch == 1:
|
139
|
-
break
|
140
|
-
else:
|
141
|
-
logging.info("4、结束...")
|
142
|
-
|
143
|
-
total = total + records
|
144
|
-
logging.info("5、{} 抓取数据 {} 条记录...".format(symbol, records))
|
145
|
-
|
146
|
-
logging.info("6、{} 抓取数据 {} 条记录...".format(symbol, total))
|
147
|
-
logging.info("{} symbol --------------------------------- ".format(symbol))
|
openfund/core/libs/__init__.py
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
import ssl
|
3
|
-
import os
|
4
|
-
import sys
|
5
|
-
import logging
|
6
|
-
|
7
|
-
import smtplib
|
8
|
-
|
9
|
-
from email.mime.text import MIMEText
|
10
|
-
|
11
|
-
from email.header import Header
|
12
|
-
from email.message import EmailMessage
|
13
|
-
import time
|
14
|
-
|
15
|
-
# app = "email_tools"
|
16
|
-
# logging.basicConfig(
|
17
|
-
# format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
|
18
|
-
# datefmt="%Y-%m-%d %H:%M:%S",
|
19
|
-
# level=logging.DEBUG,
|
20
|
-
# )
|
21
|
-
|
22
|
-
curPath = os.path.abspath(os.path.dirname(__file__))
|
23
|
-
sys.path.append(curPath)
|
24
|
-
|
25
|
-
from prepare_env import get_mail
|
26
|
-
|
27
|
-
# logging.info("---- Read config.ini -----")
|
28
|
-
(email_address, email_password, email_receiver) = get_mail()
|
29
|
-
# logging.info(
|
30
|
-
# "---- Read config.ini Finish!----{0}||{1}".format(email_address, email_receiver)
|
31
|
-
# )
|
32
|
-
|
33
|
-
|
34
|
-
def mail(topic, content):
|
35
|
-
EMAIL_ADDRESS = email_address
|
36
|
-
EMAIL_PASSWORD = email_password
|
37
|
-
context = ssl.create_default_context()
|
38
|
-
sender = EMAIL_ADDRESS
|
39
|
-
receiver = email_receiver.split(",")
|
40
|
-
|
41
|
-
subject = topic
|
42
|
-
body = content
|
43
|
-
msg = EmailMessage()
|
44
|
-
msg["subject"] = subject
|
45
|
-
msg["From"] = sender
|
46
|
-
msg["To"] = receiver
|
47
|
-
msg.set_content(body)
|
48
|
-
|
49
|
-
with smtplib.SMTP_SSL("smtp.qq.com", 465, context=context) as smtp:
|
50
|
-
smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
|
51
|
-
smtp.send_message(msg)
|
52
|
-
print("---- send_message ----\n{0}".format(msg))
|
53
|
-
|
54
|
-
|
55
|
-
if __name__ == "__main__":
|
56
|
-
mail("QRR", "BTCUSDT [2023-12-04 21:44:59 ~ 2023-12-04 21:39:59],QRR=9.4 > 5")
|
openfund/core/libs/file_tools.py
DELETED
openfund/core/libs/log_tools.py
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
import sys
|
3
|
-
import os
|
4
|
-
|
5
|
-
from loguru import logger
|
6
|
-
from datetime import datetime
|
7
|
-
|
8
|
-
# log_path = "F:\PythonProject\Logs\\"
|
9
|
-
from prepare_env import get_path
|
10
|
-
|
11
|
-
|
12
|
-
class Logger:
|
13
|
-
def __init__(self, log_name):
|
14
|
-
data_path, log_path = get_path()
|
15
|
-
self.logger = logger # 初始化一个logger
|
16
|
-
self.logger.remove() # 清空所有设置
|
17
|
-
# 添加控制台输出的格式,sys.stdout为输出到屏幕
|
18
|
-
self.logger.add(
|
19
|
-
sys.stdout,
|
20
|
-
format="<green>{time:YYYYMMDD HH:mm:ss}</green> | " # 颜色>时间
|
21
|
-
"{process.name} | " # 进程名
|
22
|
-
"{thread.name} | " # 进程名
|
23
|
-
"<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名
|
24
|
-
":<cyan>{line}</cyan> | " # 行号
|
25
|
-
"<level>{level}</level>: " # 等级
|
26
|
-
"<level>{message}</level>", # 日志内容
|
27
|
-
)
|
28
|
-
# 输出到文件
|
29
|
-
rq = datetime.now().strftime("%Y%m%d")
|
30
|
-
if not log_path.endswith("/"):
|
31
|
-
log_path = log_path + "/"
|
32
|
-
file_name = log_path + log_name + "_" + rq + ".log" # 文件名称
|
33
|
-
self.logger.add(
|
34
|
-
file_name,
|
35
|
-
level="INFO",
|
36
|
-
format="{time:YYYYMMDD HH:mm:ss} - " # 时间
|
37
|
-
"{process.name} | " # 进程名
|
38
|
-
"{thread.name} | " # 进程名
|
39
|
-
"{module}.{function}:{line} - {level} -{message}", # 模块名.方法名:行号
|
40
|
-
rotation="50 MB",
|
41
|
-
compression="tar.gz",
|
42
|
-
)
|
43
|
-
|
44
|
-
def get_log(self):
|
45
|
-
return self.logger
|
@@ -1,28 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
|
3
|
-
import os
|
4
|
-
import pathlib
|
5
|
-
from configparser import ConfigParser
|
6
|
-
|
7
|
-
config = ConfigParser()
|
8
|
-
config_file_path = os.path.join(
|
9
|
-
pathlib.Path(__file__).parent.resolve(), "..", "config.ini"
|
10
|
-
)
|
11
|
-
config.read(config_file_path)
|
12
|
-
|
13
|
-
|
14
|
-
def get_api_key():
|
15
|
-
|
16
|
-
return config["keys"]["api_key"], config["keys"]["api_secret"]
|
17
|
-
|
18
|
-
|
19
|
-
def get_path():
|
20
|
-
return config["path"]["data_path"], config["path"]["log_path"]
|
21
|
-
|
22
|
-
|
23
|
-
def get_mail():
|
24
|
-
return (
|
25
|
-
config["mail"]["email_address"],
|
26
|
-
config["mail"]["email_password"],
|
27
|
-
config["mail"]["email_receiver"],
|
28
|
-
)
|
openfund/core/libs/time.py
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
import logging
|
3
|
-
import time
|
4
|
-
|
5
|
-
from binance.cm_futures import CMFutures
|
6
|
-
from binance.lib.utils import config_logging
|
7
|
-
|
8
|
-
config_logging(logging, logging.DEBUG)
|
9
|
-
|
10
|
-
cm_futures_client = CMFutures(show_limit_usage=True)
|
11
|
-
|
12
|
-
logging.info(cm_futures_client.time())
|
13
|
-
|
14
|
-
|
openfund/core/libs/time_tools.py
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
|
3
|
-
import time
|
4
|
-
from datetime import date, datetime, timedelta
|
5
|
-
|
6
|
-
|
7
|
-
def print_timestamp(timestamp):
|
8
|
-
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp / 1000)))
|
9
|
-
|
10
|
-
|
11
|
-
def format_timestamp(timestamp):
|
12
|
-
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp / 1000))
|
13
|
-
|
14
|
-
|
15
|
-
def format_date(timestamp):
|
16
|
-
return time.strftime("%Y-%m-%d", time.localtime(timestamp / 1000))
|
17
|
-
|
18
|
-
|
19
|
-
def format_date_to(to_days):
|
20
|
-
now = date.today()
|
21
|
-
to = now + timedelta(days=to_days)
|
22
|
-
return to
|
openfund/core/sample/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
from .sample import *
|
openfund/core/sample/sample.py
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# sample.py
|
2
|
-
|
3
|
-
# create a variable in the module
|
4
|
-
sample_variable = "This is a string variable in the sample.py module"
|
5
|
-
|
6
|
-
# A function in the module
|
7
|
-
def say_hello(name):
|
8
|
-
return f"Hello, {name} welcome to this simple module."
|
9
|
-
|
10
|
-
# This is another function in the module
|
11
|
-
def add(a, b):
|
12
|
-
return f"{a} + {b} is = {a+b}"
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# print(sample_variable)
|
19
|
-
# print(say_hello("小明"))
|
20
|
-
# print(add(2, 3))
|
@@ -1,35 +0,0 @@
|
|
1
|
-
openfund/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
openfund/core/binance_tools/__init__.py,sha256=paV2IWM0QkD0ddq0UWdbsDeQTW3OBAPjMf51V5yMRgI,458
|
3
|
-
openfund/core/binance_tools/binance_tools.py,sha256=sZqO8G3c_icGcQ2MRC9IgKXOXVlenCrXndG2fzi5Km4,1162
|
4
|
-
openfund/core/binance_tools/continuous_klines.py,sha256=bUkqG5j8bJ2SCav4uKv1jDjGJ1Sk8P8VeAXiSjGpD_c,4816
|
5
|
-
openfund/core/factory.py,sha256=0YXOvouwNeFLwpalD7B6t6X8vvjqOnhNakchEuK2Uog,837
|
6
|
-
openfund/core/libs/__init__.py,sha256=QrVRHJhxr4dGr565neJweoOSKFHucVEo6-RMEvYLkNo,134
|
7
|
-
openfund/core/libs/email_tools.py,sha256=KiGaJIb0nCE0G-jka5SFtO8Mtng6nrhin2Y44-1ddxA,1411
|
8
|
-
openfund/core/libs/enums.py,sha256=WaPk56JowNe8g2wFhdSkrwLrt3Ic6HI8dDEldTKqddA,8902
|
9
|
-
openfund/core/libs/file_tools.py,sha256=oHVtqRe7ag54JmyB6EI9SSfcCoZuDjytsO7DiwuQ468,145
|
10
|
-
openfund/core/libs/log_tools.py,sha256=YWuGZYTuc4qgr0uL6ej299ox8FpNEg_uaEOBrBeQ0HI,1570
|
11
|
-
openfund/core/libs/prepare_env.py,sha256=_R0SSCy1BaE71QTUe1gRiFqNTsCpQ2vgEujBS3jtEHo,576
|
12
|
-
openfund/core/libs/time.py,sha256=HmqFzkJKSJ_H6irLfZV4oTvo0NHyRO-CeU8DMyJr_yg,272
|
13
|
-
openfund/core/libs/time_tools.py,sha256=t2LWuv41P7lfJDys9wDkp3y_LZK24DiflTvnK-eJsnM,519
|
14
|
-
openfund/core/openfund_old/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
-
openfund/core/openfund_old/continuous_klines.py,sha256=KaGW4bo88RVEg0e_Cvpg8nvQD8qkGt4k_yLvtvzFCeU,4954
|
16
|
-
openfund/core/openfund_old/depth.py,sha256=L6yejSRpd37fmAk7Qowaxw1ELPwDGxKE0JCtlkJ00YE,2682
|
17
|
-
openfund/core/openfund_old/historical_trades.py,sha256=JhvhyDp4CVG1gRhlKBaa01DWGWRHnMO3AV_PORTkkIw,4243
|
18
|
-
openfund/core/openfund_old/index_info.py,sha256=idJCW5vvVZpMjmlXpu24emRC8MH2dcEUZq2YnaDB1q4,1766
|
19
|
-
openfund/core/openfund_old/index_price_kline.py,sha256=rAqG3HGZT4SzSPAN_Hk3GLSt-oh_-Fc4h4n9W4iQKKE,3952
|
20
|
-
openfund/core/openfund_old/klines.py,sha256=O_NtJD53HTJL3CTXkV5TrhAe2WBbcVhKA-3sCLaCJY8,3136
|
21
|
-
openfund/core/openfund_old/klines_qrr.py,sha256=OK2SQuUpAb6PCOP8H-60kQE23nM9dB91pDlduH_AowE,3230
|
22
|
-
openfund/core/openfund_old/mark_price.py,sha256=wjLx4Vw_S6Ee1-yIwsOKkiX1R6iaebQAuteQibJAhR8,3535
|
23
|
-
openfund/core/openfund_old/mark_price_klines.py,sha256=FfQW3oh-XM2eR2dV5HAgJYu66ZPdWMVPVgbqe0-kc-c,4017
|
24
|
-
openfund/core/openfund_old/ticker_24hr_price_change.py,sha256=SDv68uPN1OGTN_Dukl3AK7awE1nZuxxho-1PckhZptk,2607
|
25
|
-
openfund/core/pyopenfund.py,sha256=SoIHAOMx3pAgG80mT-Ku0A1MB7RNoolC-9VcdwL_kZQ,726
|
26
|
-
openfund/core/sample/__init__.py,sha256=9V4H_36LT47CTXTn7lOmAtboIGLyVu5WaV7xj_E-04k,22
|
27
|
-
openfund/core/sample/sample.py,sha256=UstbqxMwiM_UMiQM0SZLxPqi2Vyb96SL8Xe-QxXksjs,393
|
28
|
-
openfund/core/sycu_exam/__init__.py,sha256=uLZK-YxXqXfAtTTekgfnfqRIdVedM9SBHnmGD3j5sYM,20
|
29
|
-
openfund/core/sycu_exam/exam.py,sha256=x7E3r6DgTMnlUz9q6fVysCPSabp-pQUqhGKw0xRpFrU,395
|
30
|
-
openfund/core/sycu_exam/random_grade_cplus.py,sha256=8FIUnF4ys-at2tAtg0yYXru_mmxhs20ywG5DY9TiHWo,9487
|
31
|
-
openfund/core/sycu_exam/random_grade_web.py,sha256=A2x9-jFx6L_AKAmWGrIrKcc9httJHTA5i0Uc8nGiPTE,8572
|
32
|
-
openfund_core-0.0.2.dist-info/LICENSE,sha256=xazLvYVG6Uw0rtJK_miaYXYn0Y7tWmxIJ35I21fCOFE,11356
|
33
|
-
openfund_core-0.0.2.dist-info/METADATA,sha256=cQxMF7v_YqW0eVeZWcre49kqjyW7Otxz5rDAffLD5ok,3160
|
34
|
-
openfund_core-0.0.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
35
|
-
openfund_core-0.0.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|