bullishpy 0.10.0__py3-none-any.whl → 0.11.0__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 bullishpy might be problematic. Click here for more details.
- bullish/analysis/predefined_filters.py +132 -15
- bullish/app/app.py +20 -6
- {bullishpy-0.10.0.dist-info → bullishpy-0.11.0.dist-info}/METADATA +1 -1
- {bullishpy-0.10.0.dist-info → bullishpy-0.11.0.dist-info}/RECORD +6 -6
- {bullishpy-0.10.0.dist-info → bullishpy-0.11.0.dist-info}/WHEEL +0 -0
- {bullishpy-0.10.0.dist-info → bullishpy-0.11.0.dist-info}/entry_points.txt +0 -0
|
@@ -70,15 +70,61 @@ SHOOTING_STARS = NamedFilterQuery(
|
|
|
70
70
|
order_by_asc="last_price",
|
|
71
71
|
)
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
RSI_CROSSOVER_TECH = NamedFilterQuery(
|
|
74
74
|
name="RSI cross-over",
|
|
75
75
|
cash_flow=["positive_free_cash_flow"],
|
|
76
76
|
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
77
77
|
return_after_rsi_crossover_45_period_90=[0.0, 100],
|
|
78
78
|
rsi_bullish_crossover_45=DATE_THRESHOLD,
|
|
79
|
-
market_capitalization=[
|
|
79
|
+
market_capitalization=[5e8, 1e11], # 1 billion to 1 trillion
|
|
80
|
+
order_by_desc="market_capitalization",
|
|
81
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
82
|
+
industry=[
|
|
83
|
+
"Semiconductors",
|
|
84
|
+
"Software - Application",
|
|
85
|
+
"Software - Infrastructure",
|
|
86
|
+
"Biotechnology",
|
|
87
|
+
"Diagnostics & Research",
|
|
88
|
+
"Medical Devices",
|
|
89
|
+
"Health Information Services",
|
|
90
|
+
"Internet Retail",
|
|
91
|
+
"Electronic Gaming & Multimedia",
|
|
92
|
+
"Internet Content & Information",
|
|
93
|
+
"Solar",
|
|
94
|
+
"Information Technology Services",
|
|
95
|
+
"Scientific & Technical Instruments",
|
|
96
|
+
"Semiconductor Equipment & Materials",
|
|
97
|
+
"Diagnostics & Research",
|
|
98
|
+
],
|
|
99
|
+
)
|
|
100
|
+
RSI_CROSSOVER_TECH_PE = NamedFilterQuery(
|
|
101
|
+
name="RSI cross-over P/E",
|
|
102
|
+
cash_flow=["positive_free_cash_flow"],
|
|
103
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
104
|
+
price_per_earning_ratio=[5, 30], # P/E ratio between 10 and 100
|
|
105
|
+
rsi_bullish_crossover_45=DATE_THRESHOLD,
|
|
106
|
+
market_capitalization=[5e8, 1e12], # 1 billion to 1 trillion
|
|
80
107
|
order_by_desc="market_capitalization",
|
|
108
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
109
|
+
industry=[
|
|
110
|
+
"Semiconductors",
|
|
111
|
+
"Software - Application",
|
|
112
|
+
"Software - Infrastructure",
|
|
113
|
+
"Biotechnology",
|
|
114
|
+
"Diagnostics & Research",
|
|
115
|
+
"Medical Devices",
|
|
116
|
+
"Health Information Services",
|
|
117
|
+
"Internet Retail",
|
|
118
|
+
"Electronic Gaming & Multimedia",
|
|
119
|
+
"Internet Content & Information",
|
|
120
|
+
"Solar",
|
|
121
|
+
"Information Technology Services",
|
|
122
|
+
"Scientific & Technical Instruments",
|
|
123
|
+
"Semiconductor Equipment & Materials",
|
|
124
|
+
"Diagnostics & Research",
|
|
125
|
+
],
|
|
81
126
|
)
|
|
127
|
+
|
|
82
128
|
MICRO_CAP_EVENT_SPECULATION = NamedFilterQuery(
|
|
83
129
|
name="Micro-Cap Event Speculation",
|
|
84
130
|
description="seeks tiny names where unusual volume and price gaps hint at "
|
|
@@ -185,23 +231,94 @@ OVERSOLD_MEAN_REVERSION = NamedFilterQuery(
|
|
|
185
231
|
mfi_oversold=DATE_THRESHOLD,
|
|
186
232
|
lower_than_200_day_high=DATE_THRESHOLD,
|
|
187
233
|
)
|
|
234
|
+
RSI_CROSSOVER_30_GROWTH_STOCK_STRONG_FUNDAMENTAL = NamedFilterQuery(
|
|
235
|
+
name="RSI cross-over 30 growth stock strong fundamental",
|
|
236
|
+
income=[
|
|
237
|
+
"positive_operating_income",
|
|
238
|
+
"growing_operating_income",
|
|
239
|
+
"positive_net_income",
|
|
240
|
+
"growing_net_income",
|
|
241
|
+
],
|
|
242
|
+
cash_flow=["positive_free_cash_flow"],
|
|
243
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
244
|
+
price_per_earning_ratio=[20, 40],
|
|
245
|
+
rsi_bullish_crossover_30=DATE_THRESHOLD,
|
|
246
|
+
market_capitalization=[5e8, 1e12],
|
|
247
|
+
order_by_desc="market_capitalization",
|
|
248
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
249
|
+
)
|
|
250
|
+
RSI_CROSSOVER_40_GROWTH_STOCK_STRONG_FUNDAMENTAL = NamedFilterQuery(
|
|
251
|
+
name="RSI cross-over 40 growth stock strong fundamental",
|
|
252
|
+
income=[
|
|
253
|
+
"positive_operating_income",
|
|
254
|
+
"growing_operating_income",
|
|
255
|
+
"positive_net_income",
|
|
256
|
+
"growing_net_income",
|
|
257
|
+
],
|
|
258
|
+
cash_flow=["positive_free_cash_flow"],
|
|
259
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
260
|
+
price_per_earning_ratio=[20, 40],
|
|
261
|
+
rsi_bullish_crossover_40=DATE_THRESHOLD,
|
|
262
|
+
market_capitalization=[5e8, 1e12],
|
|
263
|
+
order_by_desc="market_capitalization",
|
|
264
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
265
|
+
)
|
|
266
|
+
RSI_CROSSOVER_45_GROWTH_STOCK_STRONG_FUNDAMENTAL = NamedFilterQuery(
|
|
267
|
+
name="RSI cross-over 45 growth stock strong fundamental",
|
|
268
|
+
income=[
|
|
269
|
+
"positive_operating_income",
|
|
270
|
+
"growing_operating_income",
|
|
271
|
+
"positive_net_income",
|
|
272
|
+
"growing_net_income",
|
|
273
|
+
],
|
|
274
|
+
cash_flow=["positive_free_cash_flow"],
|
|
275
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
276
|
+
price_per_earning_ratio=[20, 40],
|
|
277
|
+
rsi_bullish_crossover_45=DATE_THRESHOLD,
|
|
278
|
+
market_capitalization=[5e8, 1e12],
|
|
279
|
+
order_by_desc="market_capitalization",
|
|
280
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
281
|
+
)
|
|
282
|
+
RSI_CROSSOVER_30_GROWTH_STOCK = NamedFilterQuery(
|
|
283
|
+
name="RSI cross-over 30 growth stock",
|
|
284
|
+
cash_flow=["positive_free_cash_flow"],
|
|
285
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
286
|
+
price_per_earning_ratio=[20, 40],
|
|
287
|
+
rsi_bullish_crossover_30=DATE_THRESHOLD,
|
|
288
|
+
market_capitalization=[5e8, 1e12],
|
|
289
|
+
order_by_desc="market_capitalization",
|
|
290
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
291
|
+
)
|
|
292
|
+
RSI_CROSSOVER_40_GROWTH_STOCK = NamedFilterQuery(
|
|
293
|
+
name="RSI cross-over 40 growth stock",
|
|
294
|
+
cash_flow=["positive_free_cash_flow"],
|
|
295
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
296
|
+
price_per_earning_ratio=[20, 40],
|
|
297
|
+
rsi_bullish_crossover_40=DATE_THRESHOLD,
|
|
298
|
+
market_capitalization=[5e8, 1e12],
|
|
299
|
+
order_by_desc="market_capitalization",
|
|
300
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
301
|
+
)
|
|
302
|
+
RSI_CROSSOVER_45_GROWTH_STOCK = NamedFilterQuery(
|
|
303
|
+
name="RSI cross-over 45 growth stock",
|
|
304
|
+
cash_flow=["positive_free_cash_flow"],
|
|
305
|
+
properties=["operating_cash_flow_is_higher_than_net_income"],
|
|
306
|
+
price_per_earning_ratio=[20, 40],
|
|
307
|
+
rsi_bullish_crossover_45=DATE_THRESHOLD,
|
|
308
|
+
market_capitalization=[5e8, 1e12],
|
|
309
|
+
order_by_desc="market_capitalization",
|
|
310
|
+
country=["Germany", "United states", "France", "United kingdom", "Canada", "Japan"],
|
|
311
|
+
)
|
|
188
312
|
|
|
189
313
|
|
|
190
314
|
def predefined_filters() -> list[NamedFilterQuery]:
|
|
191
315
|
return [
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
HIGH_QUALITY_CASH_GENERATOR,
|
|
199
|
-
EARNINGS_ACCELERATION_TREND_CONFIRMATION,
|
|
200
|
-
DIVIDEND_GROWTH_COMPOUNDER,
|
|
201
|
-
BREAK_OUT_MOMENTUM,
|
|
202
|
-
OVERSOLD_MEAN_REVERSION,
|
|
203
|
-
SHOOTING_STARS,
|
|
204
|
-
RSI_CROSSOVER,
|
|
316
|
+
RSI_CROSSOVER_30_GROWTH_STOCK_STRONG_FUNDAMENTAL,
|
|
317
|
+
RSI_CROSSOVER_40_GROWTH_STOCK_STRONG_FUNDAMENTAL,
|
|
318
|
+
RSI_CROSSOVER_45_GROWTH_STOCK_STRONG_FUNDAMENTAL,
|
|
319
|
+
RSI_CROSSOVER_30_GROWTH_STOCK,
|
|
320
|
+
RSI_CROSSOVER_40_GROWTH_STOCK,
|
|
321
|
+
RSI_CROSSOVER_45_GROWTH_STOCK,
|
|
205
322
|
]
|
|
206
323
|
|
|
207
324
|
|
bullish/app/app.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import shelve
|
|
2
3
|
import uuid
|
|
3
4
|
from pathlib import Path
|
|
@@ -37,6 +38,7 @@ CACHE_SHELVE = "user_cache"
|
|
|
37
38
|
DB_KEY = "db_path"
|
|
38
39
|
|
|
39
40
|
st.set_page_config(layout="wide")
|
|
41
|
+
logger = logging.getLogger(__name__)
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
@st.cache_resource
|
|
@@ -146,10 +148,11 @@ def build_filter(model: Type[BaseModel], data: Dict[str, Any]) -> Dict[str, Any]
|
|
|
146
148
|
key=hash((model.__name__, field)),
|
|
147
149
|
)
|
|
148
150
|
elif info.annotation == Optional[str]: # type: ignore
|
|
151
|
+
options = ["", *groups_mapping()[field]]
|
|
149
152
|
data[field] = st.selectbox(
|
|
150
153
|
name,
|
|
151
|
-
|
|
152
|
-
index=0 if not default else
|
|
154
|
+
options,
|
|
155
|
+
index=0 if not default else options.index(default),
|
|
153
156
|
key=hash((model.__name__, field)),
|
|
154
157
|
)
|
|
155
158
|
|
|
@@ -162,11 +165,22 @@ def build_filter(model: Type[BaseModel], data: Dict[str, Any]) -> Dict[str, Any]
|
|
|
162
165
|
(item.le for item in info.metadata if hasattr(item, "le")),
|
|
163
166
|
info.default[1] if info.default and len(info.default) == 2 else None,
|
|
164
167
|
)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
+
if info.annotation == Optional[List[float]]: # type: ignore
|
|
169
|
+
ge = int(ge) # type: ignore
|
|
170
|
+
le = int(le) # type: ignore
|
|
171
|
+
default = [int(d) for d in default]
|
|
172
|
+
try:
|
|
173
|
+
data[field] = list(
|
|
174
|
+
st.slider( # type: ignore
|
|
175
|
+
name, ge, le, tuple(default), key=hash((model.__name__, field))
|
|
176
|
+
)
|
|
168
177
|
)
|
|
169
|
-
|
|
178
|
+
except Exception as e:
|
|
179
|
+
logger.error(
|
|
180
|
+
f"Error building filter for {model.__name__}.{field} "
|
|
181
|
+
f"with the parameters {(info.annotation, name, ge, le, tuple(default))}: {e}"
|
|
182
|
+
)
|
|
183
|
+
raise e
|
|
170
184
|
return data
|
|
171
185
|
|
|
172
186
|
|
|
@@ -4,9 +4,9 @@ bullish/analysis/analysis.py,sha256=9ugJp2fGuA6xFUlGIJVIHWZ8d8E6TdbQHWjg5zWPIwY,
|
|
|
4
4
|
bullish/analysis/filter.py,sha256=S8TuxoTAUY0U8ARPjNHE0tSSE_ToWkfZazAgnfgswk4,18136
|
|
5
5
|
bullish/analysis/functions.py,sha256=KKz_0C7maQmcGu2tGwZvioxzmh-JcB-YNpPQGjyyheA,13825
|
|
6
6
|
bullish/analysis/indicators.py,sha256=hZgzTq-80XPP6x7dXGhxd-Zzgra-6D-g3pVxUBYOW44,20167
|
|
7
|
-
bullish/analysis/predefined_filters.py,sha256=
|
|
7
|
+
bullish/analysis/predefined_filters.py,sha256=3O244FCZkbnTSaReh6w6cwEIXdLzQZmbkBS0uRW-Y0M,12391
|
|
8
8
|
bullish/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
bullish/app/app.py,sha256=
|
|
9
|
+
bullish/app/app.py,sha256=E0H78LOODl1H6s308jXpQGTUoFPoLOJkPBXOLQGLCeA,13331
|
|
10
10
|
bullish/cli.py,sha256=uYLZmGDAolZKWzduZ58bP-xul1adg0oKfeUQtZMXTvA,1958
|
|
11
11
|
bullish/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
bullish/database/alembic/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
|
|
@@ -40,7 +40,7 @@ bullish/jobs/models.py,sha256=ndrGTMP08S57yGLGEG9TQt8Uw2slc4HvbG-TZtEEuN0,744
|
|
|
40
40
|
bullish/jobs/tasks.py,sha256=V_b0c8_GQC0-KIxaHDlLFhtkclQJOsck0gXaW6OlC_w,3055
|
|
41
41
|
bullish/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
bullish/utils/checks.py,sha256=Va10_xDVVnxYkOD2hafvyQ-TFV8FQpOkr4huJ7XgpDM,2188
|
|
43
|
-
bullishpy-0.
|
|
44
|
-
bullishpy-0.
|
|
45
|
-
bullishpy-0.
|
|
46
|
-
bullishpy-0.
|
|
43
|
+
bullishpy-0.11.0.dist-info/METADATA,sha256=2eQfm9prQaZjTnRzLUDvRd0jjE8EapQ1RMhJtQ0CXjQ,745
|
|
44
|
+
bullishpy-0.11.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
45
|
+
bullishpy-0.11.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
|
|
46
|
+
bullishpy-0.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|