siglab-py 0.1.21__py3-none-any.whl → 0.1.23__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.
Potentially problematic release.
This version of siglab-py might be problematic. Click here for more details.
- siglab_py/market_data_providers/futu_candles.py +108 -16
- siglab_py/util/analytic_util.py +1 -1
- siglab_py/util/market_data_util.py +1 -1
- {siglab_py-0.1.21.dist-info → siglab_py-0.1.23.dist-info}/METADATA +1 -1
- {siglab_py-0.1.21.dist-info → siglab_py-0.1.23.dist-info}/RECORD +7 -7
- {siglab_py-0.1.21.dist-info → siglab_py-0.1.23.dist-info}/WHEEL +0 -0
- {siglab_py-0.1.21.dist-info → siglab_py-0.1.23.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import logging
|
|
1
3
|
import argparse
|
|
2
4
|
from datetime import datetime
|
|
3
5
|
from typing import Dict, Union
|
|
6
|
+
from enum import Enum
|
|
4
7
|
import asyncio
|
|
5
8
|
|
|
6
9
|
from futu import *
|
|
@@ -9,22 +12,12 @@ from siglab_py.exchanges.futubull import Futubull
|
|
|
9
12
|
from siglab_py.util.market_data_util import fetch_candles
|
|
10
13
|
from siglab_py.util.analytic_util import compute_candles_stats
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
'''
|
|
16
|
+
Usage:
|
|
17
|
+
python futu_candles.py --symbol HK.00700 --end_date 2025-03-11 --start_date 2024-03-11 --market HK --trdmarket HK --security_firm FUTUSECURITIES --security_type STOCK --compute_ta Y
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
'symbol' : None,
|
|
17
|
-
'trdmarket' : TrdMarket.HK,
|
|
18
|
-
'security_firm' : SecurityFirm.FUTUSECURITIES,
|
|
19
|
-
'market' : Market.HK,
|
|
20
|
-
'security_type' : SecurityType.STOCK,
|
|
21
|
-
'daemon' : {
|
|
22
|
-
'host' : '127.0.0.1',
|
|
23
|
-
'port' : 11111
|
|
24
|
-
}
|
|
25
|
-
}
|
|
19
|
+
This script is NOT pypy compatible.
|
|
26
20
|
|
|
27
|
-
'''
|
|
28
21
|
If debugging from VSCode, launch.json:
|
|
29
22
|
|
|
30
23
|
{
|
|
@@ -38,10 +31,13 @@ If debugging from VSCode, launch.json:
|
|
|
38
31
|
"console": "integratedTerminal",
|
|
39
32
|
"args" : [
|
|
40
33
|
"--symbol", "HK.00700",
|
|
34
|
+
"--end_date", "2025-03-11 0:0:0",
|
|
35
|
+
"--start_date", "2024-03-11 0:0:0",
|
|
41
36
|
"--market", "HK",
|
|
42
37
|
"--trdmarket", "HK",
|
|
43
38
|
"--security_firm", "FUTUSECURITIES",
|
|
44
|
-
"--security_type", "STOCK"
|
|
39
|
+
"--security_type", "STOCK",
|
|
40
|
+
"--compute_ta", "Y"
|
|
45
41
|
],
|
|
46
42
|
"env": {
|
|
47
43
|
"PYTHONPATH": "${workspaceFolder}"
|
|
@@ -50,9 +46,59 @@ If debugging from VSCode, launch.json:
|
|
|
50
46
|
]
|
|
51
47
|
}
|
|
52
48
|
'''
|
|
49
|
+
end_date : datetime = datetime.today()
|
|
50
|
+
end_date = datetime(end_date.year, end_date.month, end_date.day)
|
|
51
|
+
start_date : datetime = end_date - timedelta(days=365)
|
|
52
|
+
|
|
53
|
+
param : Dict = {
|
|
54
|
+
'symbol' : None,
|
|
55
|
+
'start_date' : start_date,
|
|
56
|
+
'end_date' : end_date,
|
|
57
|
+
'trdmarket' : TrdMarket.HK,
|
|
58
|
+
'security_firm' : SecurityFirm.FUTUSECURITIES,
|
|
59
|
+
'market' : Market.HK,
|
|
60
|
+
'security_type' : SecurityType.STOCK,
|
|
61
|
+
'daemon' : {
|
|
62
|
+
'host' : '127.0.0.1',
|
|
63
|
+
'port' : 11111
|
|
64
|
+
},
|
|
65
|
+
'output_filename' : 'candles_$SYMBOL$.csv'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class LogLevel(Enum):
|
|
69
|
+
CRITICAL = 50
|
|
70
|
+
ERROR = 40
|
|
71
|
+
WARNING = 30
|
|
72
|
+
INFO = 20
|
|
73
|
+
DEBUG = 10
|
|
74
|
+
NOTSET = 0
|
|
75
|
+
|
|
76
|
+
logging.Formatter.converter = time.gmtime
|
|
77
|
+
logger = logging.getLogger()
|
|
78
|
+
log_level = logging.INFO # DEBUG --> INFO --> WARNING --> ERROR
|
|
79
|
+
logger.setLevel(log_level)
|
|
80
|
+
format_str = '%(asctime)s %(message)s'
|
|
81
|
+
formatter = logging.Formatter(format_str)
|
|
82
|
+
sh = logging.StreamHandler()
|
|
83
|
+
sh.setLevel(log_level)
|
|
84
|
+
sh.setFormatter(formatter)
|
|
85
|
+
logger.addHandler(sh)
|
|
86
|
+
|
|
87
|
+
def log(message : str, log_level : LogLevel = LogLevel.INFO):
|
|
88
|
+
if log_level.value<LogLevel.WARNING.value:
|
|
89
|
+
logger.info(f"{datetime.now()} {message}")
|
|
90
|
+
|
|
91
|
+
elif log_level.value==LogLevel.WARNING.value:
|
|
92
|
+
logger.warning(f"{datetime.now()} {message}")
|
|
93
|
+
|
|
94
|
+
elif log_level.value==LogLevel.ERROR.value:
|
|
95
|
+
logger.error(f"{datetime.now()} {message}")
|
|
96
|
+
|
|
53
97
|
def parse_args():
|
|
54
98
|
parser = argparse.ArgumentParser() # type: ignore
|
|
55
99
|
parser.add_argument("--symbol", help="symbol, example HK.00700", default=None)
|
|
100
|
+
parser.add_argument("--start_date", help="Format: %Y-%m-%d %H:%M:%S", default=None)
|
|
101
|
+
parser.add_argument("--end_date", help="Format: %Y-%m-%d %H:%M:%S", default=None)
|
|
56
102
|
|
|
57
103
|
'''
|
|
58
104
|
Enums here:
|
|
@@ -64,15 +110,44 @@ def parse_args():
|
|
|
64
110
|
parser.add_argument("--security_firm", help="security_firm: FUTUSECURITIES (HK), FUTUINC (US), FUTUSG (SG), FUTUAU (AU)", default=SecurityFirm.FUTUSECURITIES)
|
|
65
111
|
parser.add_argument("--security_type", help="STOCK, BOND, ETF, FUTURE, WARRANT, IDX ... ", default=SecurityType.STOCK)
|
|
66
112
|
|
|
113
|
+
parser.add_argument("--compute_ta", help="Compute technical indicators?. Y or N (default).", default='N')
|
|
114
|
+
parser.add_argument("--candle_size", help="candle interval: 1m, 1h, 1d... etc", default='1h')
|
|
115
|
+
parser.add_argument("--ma_long_intervals", help="Window size in number of intervals for higher timeframe", default=24)
|
|
116
|
+
parser.add_argument("--ma_short_intervals", help="Window size in number of intervals for lower timeframe", default=8)
|
|
117
|
+
parser.add_argument("--boillenger_std_multiples", help="Boillenger bands: # std", default=2)
|
|
118
|
+
|
|
67
119
|
args = parser.parse_args()
|
|
68
|
-
param['symbol'] = args.symbol
|
|
120
|
+
param['symbol'] = args.symbol.strip().upper()
|
|
121
|
+
|
|
122
|
+
param['start_date'] = datetime.strptime(args.start_date, "%Y-%m-%d %H:%M:%S") if args.start_date else start_date
|
|
123
|
+
param['end_date'] = datetime.strptime(args.end_date, "%Y-%m-%d %H:%M:%S") if args.end_date else end_date
|
|
124
|
+
|
|
69
125
|
param['market'] = args.market
|
|
70
126
|
param['trdmarket'] = args.trdmarket
|
|
71
127
|
param['security_firm'] = args.security_firm
|
|
72
128
|
|
|
129
|
+
param['output_filename'] = param['output_filename'].replace('$SYMBOL$', param['symbol'])
|
|
130
|
+
|
|
131
|
+
if args.compute_ta:
|
|
132
|
+
if args.compute_ta=='Y':
|
|
133
|
+
param['compute_ta'] = True
|
|
134
|
+
else:
|
|
135
|
+
param['compute_ta'] = False
|
|
136
|
+
else:
|
|
137
|
+
param['compute_ta'] = False
|
|
138
|
+
param['candle_size'] = args.candle_size
|
|
139
|
+
param['ma_long_intervals'] = int(args.ma_long_intervals)
|
|
140
|
+
param['ma_short_intervals'] = int(args.ma_short_intervals)
|
|
141
|
+
param['boillenger_std_multiples'] = int(args.boillenger_std_multiples)
|
|
142
|
+
|
|
73
143
|
async def main():
|
|
74
144
|
parse_args()
|
|
75
145
|
|
|
146
|
+
fh = logging.FileHandler(f"futu_candles.log")
|
|
147
|
+
fh.setLevel(log_level)
|
|
148
|
+
fh.setFormatter(formatter)
|
|
149
|
+
logger.addHandler(fh) # type: ignore
|
|
150
|
+
|
|
76
151
|
exchange = Futubull(param)
|
|
77
152
|
|
|
78
153
|
pd_candles: Union[pd.DataFrame, None] = fetch_candles(
|
|
@@ -92,4 +167,21 @@ async def main():
|
|
|
92
167
|
assert pd_candles['timestamp_ms'].notna().all(), "timestamp_ms column contains NaN values."
|
|
93
168
|
assert pd_candles['timestamp_ms'].is_monotonic_increasing, "Timestamps are not in ascending order."
|
|
94
169
|
|
|
170
|
+
if param['compute_ta']:
|
|
171
|
+
start = time.time()
|
|
172
|
+
compute_candles_stats(
|
|
173
|
+
pd_candles=pd_candles,
|
|
174
|
+
boillenger_std_multiples=param['boillenger_std_multiples'],
|
|
175
|
+
sliding_window_how_many_candles=param['ma_long_intervals'],
|
|
176
|
+
slow_fast_interval_ratio=(param['ma_long_intervals']/param['ma_short_intervals']),
|
|
177
|
+
pypy_compat=False
|
|
178
|
+
)
|
|
179
|
+
compute_candles_stats_elapsed_ms = int((time.time() - start) *1000)
|
|
180
|
+
log(f"TA calculated, took {compute_candles_stats_elapsed_ms} ms")
|
|
181
|
+
|
|
182
|
+
log(f"Candles (# rows: {pd_candles.shape[0]}) written to {param['output_filename']}")
|
|
183
|
+
pd_candles.to_csv(param['output_filename'])
|
|
184
|
+
|
|
185
|
+
sys.exit()
|
|
186
|
+
|
|
95
187
|
asyncio.run(main())
|
siglab_py/util/analytic_util.py
CHANGED
|
@@ -10,7 +10,7 @@ from hurst import compute_Hc # compatible with pypy
|
|
|
10
10
|
from ccxt.base.exchange import Exchange as CcxtExchange
|
|
11
11
|
from ccxt import deribit
|
|
12
12
|
|
|
13
|
-
from util.market_data_util import fix_column_types
|
|
13
|
+
from siglab_py.util.market_data_util import fix_column_types
|
|
14
14
|
|
|
15
15
|
# Fibonacci
|
|
16
16
|
MAGIC_FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.00, 1.618, 2.618, 3.618, 4.236]
|
|
@@ -15,7 +15,7 @@ from yahoofinancials import YahooFinancials
|
|
|
15
15
|
# yfinance allows intervals '1m', '5m', '15m', '1h', '1d', '1wk', '1mo'. yahoofinancials not as flexible
|
|
16
16
|
import yfinance as yf
|
|
17
17
|
|
|
18
|
-
from exchanges.futubull import Futubull
|
|
18
|
+
from siglab_py.exchanges.futubull import Futubull
|
|
19
19
|
|
|
20
20
|
def timestamp_to_datetime_cols(pd_candles : pd.DataFrame):
|
|
21
21
|
pd_candles['datetime'] = pd_candles['timestamp_ms'].apply(
|
|
@@ -8,7 +8,7 @@ siglab_py/market_data_providers/aggregated_orderbook_provider.py,sha256=FZRobEBN
|
|
|
8
8
|
siglab_py/market_data_providers/candles_provider.py,sha256=fqHJjlECsBiBlpgyywrc4gTgxiROPNzZM8KxQBB5cOg,14139
|
|
9
9
|
siglab_py/market_data_providers/candles_ta_provider.py,sha256=uiAhbEZZdTF-YulBHpSLwabos5LHCKU91NTiTmpUc0w,12001
|
|
10
10
|
siglab_py/market_data_providers/deribit_options_expiry_provider.py,sha256=e9Ee8TmC8pXaid8-jouSLKIpuW6_JBBgwRTieI665yQ,8684
|
|
11
|
-
siglab_py/market_data_providers/futu_candles.py,sha256=
|
|
11
|
+
siglab_py/market_data_providers/futu_candles.py,sha256=jdD-IOU0BJvbxq0sxPBirVDW-oYV2k8E5OGItNHfNN0,7576
|
|
12
12
|
siglab_py/market_data_providers/orderbooks_provider.py,sha256=olt-3LIkoyzQWfNNQRhJtKibLbkTutt_q_rCCTM7i1g,16216
|
|
13
13
|
siglab_py/market_data_providers/test_provider.py,sha256=wBLCgcWjs7FGZJXWsNyn30lkOLa_cgpuvqRakMC0wbA,2221
|
|
14
14
|
siglab_py/ordergateway/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -22,11 +22,11 @@ siglab_py/tests/integration/market_data_util_tests.py,sha256=5RbWkeEWPqCOXiW3e04
|
|
|
22
22
|
siglab_py/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
siglab_py/tests/unit/analytic_util_tests.py,sha256=-FGj-cWdIZ_WZQqQCIpDLRSv5TlJIG81fHyBlWuAm1U,2961
|
|
24
24
|
siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
siglab_py/util/analytic_util.py,sha256=
|
|
25
|
+
siglab_py/util/analytic_util.py,sha256=FiS7R_om3F3M8D0LbS6PbmiWy4RT1kubpgkzdbaGlTY,43448
|
|
26
26
|
siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
|
|
27
|
-
siglab_py/util/market_data_util.py,sha256=
|
|
27
|
+
siglab_py/util/market_data_util.py,sha256=AcgWueAGtC6Gm1oq06v1R0a85dz__Tp3QarVSD_iU6Q,17262
|
|
28
28
|
siglab_py/util/retry_util.py,sha256=mxYuRFZRZoaQQjENcwPmxhxixtd1TFvbxIdPx4RwfRc,743
|
|
29
|
-
siglab_py-0.1.
|
|
30
|
-
siglab_py-0.1.
|
|
31
|
-
siglab_py-0.1.
|
|
32
|
-
siglab_py-0.1.
|
|
29
|
+
siglab_py-0.1.23.dist-info/METADATA,sha256=rFMtNxP1dwVNViRngF75g8Va5BsuboilkSojaLWe6Bw,1097
|
|
30
|
+
siglab_py-0.1.23.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
31
|
+
siglab_py-0.1.23.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
|
|
32
|
+
siglab_py-0.1.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|