bullishpy 0.44.0__tar.gz → 0.46.0__tar.gz
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.
- {bullishpy-0.44.0 → bullishpy-0.46.0}/PKG-INFO +1 -1
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/predefined_filters.py +18 -6
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/cli.py +8 -1
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/jobs/tasks.py +18 -14
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/utils/checks.py +3 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/pyproject.toml +1 -1
- {bullishpy-0.44.0 → bullishpy-0.46.0}/README.md +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/analysis.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/backtest.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/constants.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/filter.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/functions.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/indicators.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/analysis/industry_views.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/app/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/app/app.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/README +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/alembic.ini +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/env.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/script.py.mako +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/037dbd721317_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/040b15fba458_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/08ac1116e055_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/11d35a452b40_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/12889a2cbd7d_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/17e51420e7ad_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/49c83f9eb5ac_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/4b0a2f40b7d3_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/5b10ee7604c1_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/6d252e23f543_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/73564b60fe24_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/79bc71ec6f9e_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/ae444f338124_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/b76079e9845f_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/bf6b86dd5463_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/d0e58e050845_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/d663166c531d_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/ec25c8fa449f_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/ee5baabb35f8_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/fc191121f522_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/alembic/versions/ff0cc4ba40ec_.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/crud.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/schemas.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/scripts/create_revision.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/scripts/stamp.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/scripts/upgrade.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/database/settings.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/exceptions.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/figures/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/figures/figures.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/interface/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/interface/interface.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/jobs/__init__.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/jobs/app.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/jobs/models.py +0 -0
- {bullishpy-0.44.0 → bullishpy-0.46.0}/bullish/utils/__init__.py +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
2
4
|
from datetime import timedelta
|
|
5
|
+
from pathlib import Path
|
|
3
6
|
from typing import Dict, Any, Optional, List, Union, get_args
|
|
4
7
|
|
|
5
8
|
from bullish.analysis.analysis import AnalysisView
|
|
@@ -141,6 +144,20 @@ class NamedFilterQuery(FilterQuery):
|
|
|
141
144
|
]
|
|
142
145
|
|
|
143
146
|
|
|
147
|
+
def load_custom_filters() -> List[NamedFilterQuery]:
|
|
148
|
+
if "CUSTOM_FILTERS_PATH" in os.environ:
|
|
149
|
+
custom_filters_path = os.environ["CUSTOM_FILTERS_PATH"]
|
|
150
|
+
return read_custom_filters(Path(custom_filters_path))
|
|
151
|
+
return []
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def read_custom_filters(custom_filters_path: Path) -> List[NamedFilterQuery]:
|
|
155
|
+
if custom_filters_path.exists():
|
|
156
|
+
filters = json.loads(custom_filters_path.read_text())
|
|
157
|
+
return [NamedFilterQuery.model_validate(filter) for filter in filters]
|
|
158
|
+
return []
|
|
159
|
+
|
|
160
|
+
|
|
144
161
|
SMALL_CAP = NamedFilterQuery(
|
|
145
162
|
name="Small Cap",
|
|
146
163
|
last_price=[1, 20],
|
|
@@ -193,11 +210,6 @@ NEXT_EARNINGS_DATE = NamedFilterQuery(
|
|
|
193
210
|
datetime.date.today() + timedelta(days=20),
|
|
194
211
|
],
|
|
195
212
|
).variants()
|
|
196
|
-
SOLD_POSITIONS = NamedFilterQuery(
|
|
197
|
-
name="Sold Positions",
|
|
198
|
-
order_by_desc="market_capitalization",
|
|
199
|
-
symbol=["R3NK.DE", "VKTX", "RHM.DE", "IQV", "DAL"],
|
|
200
|
-
).variants()
|
|
201
213
|
|
|
202
214
|
|
|
203
215
|
def predefined_filters() -> list[NamedFilterQuery]:
|
|
@@ -207,7 +219,7 @@ def predefined_filters() -> list[NamedFilterQuery]:
|
|
|
207
219
|
*TOP_PERFORMERS_YEARLY,
|
|
208
220
|
*LARGE_CAPS,
|
|
209
221
|
*NEXT_EARNINGS_DATE,
|
|
210
|
-
*
|
|
222
|
+
*load_custom_filters(),
|
|
211
223
|
]
|
|
212
224
|
|
|
213
225
|
|
|
@@ -19,17 +19,24 @@ STREAMLIT_FILE = Path(__file__).parent.joinpath("app", "app.py")
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@app.command()
|
|
22
|
-
def serve(
|
|
22
|
+
def serve( # noqa: C901
|
|
23
23
|
host: str = typer.Option("0.0.0.0", help="Streamlit host"), # noqa: S104
|
|
24
24
|
port: int = typer.Option(8501, help="Streamlit port"),
|
|
25
25
|
env_vars: Path = typer.Option( # noqa: B008
|
|
26
26
|
None, help="Environment variables file"
|
|
27
27
|
),
|
|
28
|
+
custom_filters: Path = typer.Option( # noqa: B008
|
|
29
|
+
None, help="Environment variables file"
|
|
30
|
+
),
|
|
28
31
|
) -> None:
|
|
29
32
|
if env_vars:
|
|
30
33
|
env_vars_path = Path(env_vars)
|
|
31
34
|
if env_vars_path.exists():
|
|
32
35
|
load_dotenv(dotenv_path=env_vars_path)
|
|
36
|
+
if custom_filters:
|
|
37
|
+
custom_filters_path = Path(custom_filters)
|
|
38
|
+
if custom_filters_path.exists():
|
|
39
|
+
os.environ["CUSTOM_FILTERS_PATH"] = str(custom_filters_path)
|
|
33
40
|
children: list[subprocess.Popen] = [] # type: ignore
|
|
34
41
|
|
|
35
42
|
def _shutdown(*_: Any) -> None:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import logging
|
|
3
|
+
import random
|
|
3
4
|
from typing import Optional, Any, Callable, List
|
|
4
5
|
|
|
5
6
|
from bearish.main import Bearish # type: ignore
|
|
@@ -14,7 +15,7 @@ from .models import JobTrackerStatus, JobTracker, JobType
|
|
|
14
15
|
from ..analysis.analysis import run_analysis, run_signal_series_analysis
|
|
15
16
|
from ..analysis.backtest import run_many_tests, BackTestConfig
|
|
16
17
|
from ..analysis.industry_views import compute_industry_view
|
|
17
|
-
from ..analysis.predefined_filters import predefined_filters
|
|
18
|
+
from ..analysis.predefined_filters import predefined_filters
|
|
18
19
|
from ..database.crud import BullishDb
|
|
19
20
|
from bullish.analysis.filter import FilterUpdate
|
|
20
21
|
from ..utils.checks import DataBaseSingleTon
|
|
@@ -91,9 +92,10 @@ def cron_update(
|
|
|
91
92
|
task: Optional[Task] = None,
|
|
92
93
|
) -> None:
|
|
93
94
|
database = DataBaseSingleTon()
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
if database.valid():
|
|
96
|
+
job_tracker(_base_update)(
|
|
97
|
+
database.path, "Update data", [], FilterUpdate(), task=task
|
|
98
|
+
)
|
|
97
99
|
|
|
98
100
|
|
|
99
101
|
@huey.task(context=True) # type: ignore
|
|
@@ -155,14 +157,16 @@ def news(
|
|
|
155
157
|
def cron_news(
|
|
156
158
|
task: Optional[Task] = None,
|
|
157
159
|
) -> None:
|
|
158
|
-
|
|
160
|
+
filter = random.choice(predefined_filters()) # noqa: S311
|
|
159
161
|
database = DataBaseSingleTon()
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
if database.valid():
|
|
163
|
+
bullish_db = BullishDb(database_path=database.path)
|
|
164
|
+
data = bullish_db.read_filter_query(filter)
|
|
165
|
+
if not data.empty and "symbol" in data.columns:
|
|
166
|
+
job_tracker(base_news)(
|
|
167
|
+
database_path=database.path,
|
|
168
|
+
job_type="Fetching news",
|
|
169
|
+
symbols=data["symbol"].unique().tolist(),
|
|
170
|
+
headless=False,
|
|
171
|
+
task=task,
|
|
172
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|