siglab-py 0.1.21__py3-none-any.whl → 0.1.22__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.

@@ -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
- end_date : datetime = datetime.today()
13
- start_date : datetime = end_date - timedelta(days=365)
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
- param : Dict = {
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())
@@ -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(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siglab-py
3
- Version: 0.1.21
3
+ Version: 0.1.22
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>
@@ -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=hjvbEV8nIs_v5lu8sWu_8C4cNoB82LLRXTzTiz7YZUE,3526
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
@@ -24,9 +24,9 @@ siglab_py/tests/unit/analytic_util_tests.py,sha256=-FGj-cWdIZ_WZQqQCIpDLRSv5TlJI
24
24
  siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  siglab_py/util/analytic_util.py,sha256=QLabbEMqM4rKKH2PE_LqxIyo-BUdCRhkLybLATBImcc,43438
26
26
  siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
27
- siglab_py/util/market_data_util.py,sha256=PmGPBXJDTuK-so4qoGT27ag-_Qig7GNFV6znxkmcRW4,17252
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.21.dist-info/METADATA,sha256=KsRZwN69jt6TZAKdikVr7LPL3qjf-VTpX0r5OhDU2Yk,1097
30
- siglab_py-0.1.21.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
31
- siglab_py-0.1.21.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
32
- siglab_py-0.1.21.dist-info/RECORD,,
29
+ siglab_py-0.1.22.dist-info/METADATA,sha256=6DqCwuGcaC9H-w7puMlLCsRns8_ctA1dtaHCk2EK7x4,1097
30
+ siglab_py-0.1.22.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
31
+ siglab_py-0.1.22.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
32
+ siglab_py-0.1.22.dist-info/RECORD,,