siglab-py 0.5.48__py3-none-any.whl → 0.5.50__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,7 +1,7 @@
1
1
  import unittest
2
- from typing import List
2
+ from typing import List, Dict, Union
3
3
 
4
- from util.simple_math import generate_rand_nums
4
+ from util.simple_math import generate_rand_nums, round_to_level, bucket_series
5
5
 
6
6
  class SimpleMathTests(unittest.TestCase):
7
7
 
@@ -84,4 +84,138 @@ class SimpleMathTests(unittest.TestCase):
84
84
 
85
85
  assert(len(rand_nums)==size)
86
86
  assert(len([x for x in rand_nums if x>=range_min and x<=range_max]) == (percentage_in_range/100) * size)
87
- assert(len([x for x in rand_nums if x<abs_min or x>abs_max]) == 0)
87
+ assert(len([x for x in rand_nums if x<abs_min or x>abs_max]) == 0)
88
+
89
+ def test_round_to_level(self):
90
+ prices = [
91
+ { 'price' : 15080, 'rounded' : 15000},
92
+ { 'price' : 15180, 'rounded' : 15200},
93
+ { 'price' : 25080, 'rounded' : 25200},
94
+ { 'price' : 25180, 'rounded' : 25200},
95
+ { 'price' : 25380, 'rounded' : 25500},
96
+ { 'price' : 95332, 'rounded' : 95000},
97
+ { 'price' : 95878, 'rounded' : 96000},
98
+ { 'price' : 103499, 'rounded' : 103000},
99
+ { 'price' : 103500, 'rounded' : 104000},
100
+ { 'price' : 150800, 'rounded' : 150000},
101
+ { 'price' : 151800, 'rounded' : 152000}
102
+ ]
103
+ for entry in prices:
104
+ price = entry['price']
105
+ expected = entry['rounded']
106
+ rounded_price = round_to_level(price, level_granularity=0.01)
107
+ print(f"{price} rounded to: {rounded_price}")
108
+ assert(rounded_price==expected)
109
+
110
+ def test_bucket_series(self):
111
+ range_min : float = 0
112
+ range_max : float = 1
113
+ size : int = 100
114
+ percentage_in_range : float = 91
115
+ abs_min : float = -0.5
116
+ abs_max : float = 1.1
117
+
118
+ rand_nums : List[float] = generate_rand_nums(
119
+ range_min = range_min,
120
+ range_max = range_max,
121
+ size = size,
122
+ percent_in_range = percentage_in_range,
123
+ abs_min = abs_min,
124
+ abs_max = abs_max
125
+ )
126
+
127
+ buckets : Dict[
128
+ str,
129
+ Dict[str,Union[float, List[float]]]
130
+ ] = bucket_series(
131
+ values = rand_nums,
132
+ outlier_threshold_percent = 10
133
+ )
134
+
135
+
136
+ range_min = -1
137
+ range_max = 1
138
+ size : int = 100
139
+ percentage_in_range = 91
140
+ abs_min = -1.5
141
+ abs_max = 1.5
142
+
143
+ rand_nums : List[float] = generate_rand_nums(
144
+ range_min = range_min,
145
+ range_max = range_max,
146
+ size = size,
147
+ percent_in_range = percentage_in_range,
148
+ abs_min = abs_min,
149
+ abs_max = abs_max
150
+ )
151
+
152
+ buckets = bucket_series(
153
+ values = rand_nums,
154
+ outlier_threshold_percent = 10
155
+ )
156
+
157
+
158
+ range_min = 0
159
+ range_max = 100
160
+ size : int = 100
161
+ percentage_in_range = 91
162
+ abs_min = -0.5
163
+ abs_max = 150
164
+
165
+ rand_nums : List[float] = generate_rand_nums(
166
+ range_min = range_min,
167
+ range_max = range_max,
168
+ size = size,
169
+ percent_in_range = percentage_in_range,
170
+ abs_min = abs_min,
171
+ abs_max = abs_max
172
+ )
173
+
174
+ buckets = bucket_series(
175
+ values = rand_nums,
176
+ outlier_threshold_percent = 10
177
+ )
178
+
179
+
180
+ range_min = -100
181
+ range_max = 100
182
+ size : int = 100
183
+ percentage_in_range = 91
184
+ abs_min = -150
185
+ abs_max = 150
186
+
187
+ rand_nums : List[float] = generate_rand_nums(
188
+ range_min = range_min,
189
+ range_max = range_max,
190
+ size = size,
191
+ percent_in_range = percentage_in_range,
192
+ abs_min = abs_min,
193
+ abs_max = abs_max
194
+ )
195
+
196
+ buckets = bucket_series(
197
+ values = rand_nums,
198
+ outlier_threshold_percent = 10
199
+ )
200
+
201
+
202
+ range_min = 20_000
203
+ range_max = 120_000
204
+ size : int = 100
205
+ percentage_in_range = 91
206
+ abs_min = 15_000
207
+ abs_max = 130_000
208
+
209
+ rand_nums : List[float] = generate_rand_nums(
210
+ range_min = range_min,
211
+ range_max = range_max,
212
+ size = size,
213
+ percent_in_range = percentage_in_range,
214
+ abs_min = abs_min,
215
+ abs_max = abs_max
216
+ )
217
+
218
+ buckets = bucket_series(
219
+ values = rand_nums,
220
+ outlier_threshold_percent = 10
221
+ )
@@ -63,24 +63,3 @@ class TradingUtilTests(unittest.TestCase):
63
63
  default_effective_tp_trailing_percent = default_effective_tp_trailing_percent
64
64
  )
65
65
  assert(effective_tp_trailing_percent==0) # Most tight trailing SL
66
-
67
- def test_round_to_level(self):
68
- prices = [
69
- { 'price' : 15080, 'rounded' : 15000},
70
- { 'price' : 15180, 'rounded' : 15200},
71
- { 'price' : 25080, 'rounded' : 25200},
72
- { 'price' : 25180, 'rounded' : 25200},
73
- { 'price' : 25380, 'rounded' : 25500},
74
- { 'price' : 95332, 'rounded' : 95000},
75
- { 'price' : 95878, 'rounded' : 96000},
76
- { 'price' : 103499, 'rounded' : 103000},
77
- { 'price' : 103500, 'rounded' : 104000},
78
- { 'price' : 150800, 'rounded' : 150000},
79
- { 'price' : 151800, 'rounded' : 152000}
80
- ]
81
- for entry in prices:
82
- price = entry['price']
83
- expected = entry['rounded']
84
- rounded_price = round_to_level(price, level_granularity=0.01)
85
- print(f"{price} rounded to: {rounded_price}")
86
- assert(rounded_price==expected)
@@ -1,5 +1,6 @@
1
+ import math
1
2
  import random
2
- from typing import List
3
+ from typing import List, Dict, Union
3
4
 
4
5
  def generate_rand_nums(
5
6
  range_min : float = 0,
@@ -8,7 +9,7 @@ def generate_rand_nums(
8
9
  percent_in_range : float = 100,
9
10
  abs_min : float = 0,
10
11
  abs_max : float = 1
11
- ):
12
+ ) -> List[float]:
12
13
  assert(range_min<range_max)
13
14
 
14
15
  if abs_min>range_min:
@@ -16,7 +17,7 @@ def generate_rand_nums(
16
17
  if abs_max<range_max:
17
18
  abs_max = range_max
18
19
 
19
- result = []
20
+ result : List[float] = []
20
21
  for _ in range(int(size * percent_in_range/100)):
21
22
  result.append(random.uniform(range_min, range_max))
22
23
  for _ in range(size - len(result)):
@@ -28,3 +29,164 @@ def generate_rand_nums(
28
29
  random.shuffle(result)
29
30
 
30
31
  return result
32
+
33
+ # https://norman-lm-fung.medium.com/levels-are-psychological-7176cdefb5f2
34
+ def round_to_level(
35
+ num : float,
36
+ level_granularity : float = 0.01
37
+ ) -> float:
38
+ level_size = num * level_granularity
39
+ magnitude = math.floor(math.log10(level_size))
40
+ base_increment = 10 ** magnitude
41
+ rounded_level_size = round(level_size / base_increment) * base_increment
42
+ rounded_num = round(num / rounded_level_size) * rounded_level_size
43
+ return rounded_num
44
+
45
+ def bucket_series(
46
+ values : List[float],
47
+ outlier_threshold_percent : float = 0,
48
+ level_granularity : float = 0.1 # 0.1 = 10%
49
+ ) -> Dict[
50
+ str,
51
+ Dict[str,Union[float, List[float]]]
52
+ ]:
53
+ buckets : Dict[
54
+ str,
55
+ Dict[str,Union[float, List[float]]]
56
+ ] = {}
57
+ list_0_to_1 : bool = True if len([x for x in values if x<0 or x>1])/len(values)*100 <= outlier_threshold_percent else False
58
+ list_m1_to_1 : bool = True if len([x for x in values if x<-1 or x>1])/len(values)*100 <= outlier_threshold_percent else False
59
+ list_0_to_100 : bool = True if len([x for x in values if x<0 or x>100])/len(values)*100 <= outlier_threshold_percent else False
60
+ list_m100_to_100 : bool = True if len([x for x in values if x<-100 or x>100])/len(values)*100 <= outlier_threshold_percent else False
61
+
62
+ def _generate_sequence(start, stop, step):
63
+ result = []
64
+ current = start
65
+ num_steps = int((stop - start) / step) + 1
66
+ for i in range(num_steps):
67
+ result.append(round(start + i * step, 10))
68
+ return result
69
+
70
+ if list_0_to_1:
71
+ intervals = _generate_sequence(0.1, 1, 0.1)
72
+ last_interval = 0
73
+ buckets[f"< 0"] = {
74
+ 'min' : float("-inf"),
75
+ 'max' : 0,
76
+ 'values' : [ x for x in values if x<0 ]
77
+ }
78
+ for interval in intervals:
79
+ buckets[f"{last_interval} - {interval}"] = {
80
+ 'min' : last_interval,
81
+ 'max' : interval,
82
+ 'values' : [ x for x in values if x>=last_interval and x<interval ]
83
+ }
84
+ last_interval = interval
85
+ buckets[f">1"] = {
86
+ 'min' : last_interval,
87
+ 'max' : float("inf"),
88
+ 'values' : [ x for x in values if x>=1 ]
89
+ }
90
+
91
+ elif not list_0_to_1 and list_m1_to_1:
92
+ intervals = _generate_sequence(-0.9, 1, 0.1)
93
+ last_interval = -1
94
+ buckets[f"< -1"] = {
95
+ 'min' : float("-inf"),
96
+ 'max' : -1,
97
+ 'values' : [ x for x in values if x<-1 ]
98
+ }
99
+ for interval in intervals:
100
+ buckets[f"{last_interval} - {interval}"] = {
101
+ 'min' : last_interval,
102
+ 'max' : interval,
103
+ 'values' : [ x for x in values if x>=last_interval and x<interval ]
104
+ }
105
+ last_interval = interval
106
+ buckets[f">1"] = {
107
+ 'min' : last_interval,
108
+ 'max' : float("inf"),
109
+ 'values' : [ x for x in values if x>=1 ]
110
+ }
111
+
112
+ elif not list_0_to_1 and not list_m1_to_1 and list_0_to_100:
113
+ intervals = _generate_sequence(10, 100, 10)
114
+ last_interval = 0
115
+ buckets[f"<0"] = {
116
+ 'min' : float("-inf"),
117
+ 'max' : 0,
118
+ 'values' : [ x for x in values if x<0 ]
119
+ }
120
+ for interval in intervals:
121
+ buckets[f"{last_interval} - {interval}"] = {
122
+ 'min' : last_interval,
123
+ 'max' : interval,
124
+ 'values' : [ x for x in values if x>=last_interval and x<interval ]
125
+ }
126
+ last_interval = interval
127
+ buckets[f">100"] = {
128
+ 'min' : last_interval,
129
+ 'max' : float("inf"),
130
+ 'values' : [ x for x in values if x>=100 ]
131
+ }
132
+
133
+ elif not list_0_to_1 and not list_m1_to_1 and not list_0_to_100 and list_m100_to_100:
134
+ intervals = _generate_sequence(-90, 100, 10)
135
+ last_interval = -100
136
+ buckets[f"<-100"] = {
137
+ 'min' : float("-inf"),
138
+ 'max' : -100,
139
+ 'values' : [ x for x in values if x<-100 ]
140
+ }
141
+ for interval in intervals:
142
+ buckets[f"{last_interval} - {interval}"] = {
143
+ 'min' : last_interval,
144
+ 'max' : interval,
145
+ 'values' : [ x for x in values if x>=last_interval and x<interval ]
146
+ }
147
+ last_interval = interval
148
+ buckets[f">100"] = {
149
+ 'min' : last_interval,
150
+ 'max' : float("inf"),
151
+ 'values' : [ x for x in values if x>=100 ]
152
+ }
153
+
154
+ else:
155
+ range_min = round_to_level(
156
+ min(values),
157
+ level_granularity=level_granularity
158
+ )
159
+ range_max = round_to_level(
160
+ max(values),
161
+ level_granularity=level_granularity
162
+ )
163
+ step = round_to_level(
164
+ abs(range_max - range_min) * level_granularity,
165
+ level_granularity=level_granularity
166
+ )
167
+
168
+ intervals = _generate_sequence(range_min+step, range_max, step)
169
+ last_interval = range_min
170
+ buckets[f"< {range_min}"] = {
171
+ 'min' : float("-inf"),
172
+ 'max' : range_min,
173
+ 'values' : [ x for x in values if x<range_min ]
174
+ }
175
+ for interval in intervals:
176
+ buckets[f"{last_interval} - {interval}"] = {
177
+ 'min' : last_interval,
178
+ 'max' : interval,
179
+ 'values' : [ x for x in values if x>=last_interval and x<interval ]
180
+ }
181
+ last_interval = interval
182
+ buckets[f"> {range_max}"] = {
183
+ 'min' : last_interval,
184
+ 'max' : float("inf"),
185
+ 'values' : [ x for x in values if x>=range_max ]
186
+ }
187
+
188
+ for key in buckets:
189
+ bucket = buckets[key]
190
+ assert(len([x for x in bucket['values'] if x<bucket['min'] or x>bucket['max']])==0) # type: ignore
191
+
192
+ return buckets
@@ -116,15 +116,3 @@ def calc_eff_trailing_sl(
116
116
  effective_tp_trailing_percent = default_effective_tp_trailing_percent
117
117
 
118
118
  return effective_tp_trailing_percent
119
-
120
- # https://norman-lm-fung.medium.com/levels-are-psychological-7176cdefb5f2
121
- def round_to_level(
122
- price : float,
123
- level_granularity : float = 0.01
124
- ) -> float:
125
- level_size = price * level_granularity
126
- magnitude = math.floor(math.log10(level_size))
127
- base_increment = 10 ** magnitude
128
- rounded_level_size = round(level_size / base_increment) * base_increment
129
- rounded_price = round(price / rounded_level_size) * rounded_level_size
130
- return rounded_price
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: siglab_py
3
- Version: 0.5.48
3
+ Version: 0.5.50
4
4
  Summary: Market data fetches, TA calculations and generic order gateway.
5
5
  Author: r0bbarh00d
6
6
  Author-email: r0bbarh00d <r0bbarh00d@gmail.com>
@@ -24,18 +24,18 @@ siglab_py/tests/integration/market_data_util_tests.py,sha256=p-RWIJZLyj0lAdfi4QT
24
24
  siglab_py/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  siglab_py/tests/unit/analytic_util_tests.py,sha256=K7jtuKJLynW8EFyNgjOVHA2e2d6Gl2f0ONggFy9tD7g,5780
26
26
  siglab_py/tests/unit/market_data_util_tests.py,sha256=A1y83itISmMJdn6wLpfwcr4tGola8wTf1D1xbelMvgw,2026
27
- siglab_py/tests/unit/simple_math_tests.py,sha256=nM7RZyFGNpMpAXattrO-K5gnlhYXF1trWRbETWRQiqU,3643
28
- siglab_py/tests/unit/trading_util_tests.py,sha256=9DZmTZlW55lPtNfTCukgDdiyBiMYv9R4mEFWJIJiTNg,3870
27
+ siglab_py/tests/unit/simple_math_tests.py,sha256=eKQmN9B8HxHJUfVQMYcu20P7qHYUMEvVIcKOCg--ofU,9045
28
+ siglab_py/tests/unit/trading_util_tests.py,sha256=LiflZrduWXyLMbpSFQCaydA7jdJx3vFR-3KuKRRGhjQ,2927
29
29
  siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  siglab_py/util/analytic_util.py,sha256=dlmaf4QZ95JPGNN0LgOG8njpYE9nek4g9QVA51KvM6s,61306
31
31
  siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
32
32
  siglab_py/util/market_data_util.py,sha256=mUXg4uaiX3b6_klgJWIEgnUQU4IUd6CwTOqKLiQWRlU,31307
33
33
  siglab_py/util/notification_util.py,sha256=tNZMUkkjz4q1CKqcQq62oEmZgHgNIwz2Iw9J22V22Zw,2668
34
34
  siglab_py/util/retry_util.py,sha256=g-UU6pkPouWZZRZEqP99R2Z0lX5xzckYkzjwqqSDpVQ,922
35
- siglab_py/util/simple_math.py,sha256=LUZVMEl-EA_jMgIYcqOFPgMEDRDJxFU4n_KCN1qznyw,827
35
+ siglab_py/util/simple_math.py,sha256=85qJXRsA9otKiVwFXjEQ4NX_PlFh_in2DdqpZruuw7A,7052
36
36
  siglab_py/util/slack_notification_util.py,sha256=G27n-adbT3Q6oaHSMvu_Nom794rrda5PprSF-zvmzkM,1912
37
- siglab_py/util/trading_util.py,sha256=-TGNgJdy4HMDPgq31KQn_lRawFxuXnFU5NnLRb1XM5o,5757
38
- siglab_py-0.5.48.dist-info/METADATA,sha256=kg-ba09DtS7X-RWGzHjRRhz6xmmjWy-PhS4ZYhdZzoU,829
39
- siglab_py-0.5.48.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
40
- siglab_py-0.5.48.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
41
- siglab_py-0.5.48.dist-info/RECORD,,
37
+ siglab_py/util/trading_util.py,sha256=dlIOzoMGnddLSFODcJ61EBH1Aeruq4IT2MsxIdFkV9I,5252
38
+ siglab_py-0.5.50.dist-info/METADATA,sha256=WlcUc9wwdhTQmpp_sY07SXRBA2RxqiCAcfK2Y5yZZNQ,829
39
+ siglab_py-0.5.50.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
40
+ siglab_py-0.5.50.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
41
+ siglab_py-0.5.50.dist-info/RECORD,,