bullishpy 0.55.0__py3-none-any.whl → 0.75.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/analysis.py +28 -3
- bullish/analysis/constants.py +54 -0
- bullish/analysis/filter.py +3 -1
- bullish/analysis/functions.py +37 -2
- bullish/analysis/indicators.py +23 -2
- bullish/analysis/openai.py +91 -0
- bullish/analysis/predefined_filters.py +177 -109
- bullish/app/app.py +15 -4
- bullish/database/alembic/versions/65662e214031_.py +48 -0
- bullish/database/alembic/versions/660897c02c00_.py +36 -0
- bullish/database/alembic/versions/b36c310f49ec_.py +43 -0
- bullish/database/alembic/versions/c828e29e1105_.py +87 -0
- bullish/database/alembic/versions/cc28171c21a4_.py +43 -0
- bullish/database/crud.py +53 -4
- bullish/database/schemas.py +9 -0
- bullish/figures/figures.py +28 -18
- bullish/interface/interface.py +7 -1
- bullish/jobs/tasks.py +45 -10
- {bullishpy-0.55.0.dist-info → bullishpy-0.75.0.dist-info}/METADATA +8 -6
- {bullishpy-0.55.0.dist-info → bullishpy-0.75.0.dist-info}/RECORD +23 -17
- {bullishpy-0.55.0.dist-info → bullishpy-0.75.0.dist-info}/WHEEL +1 -1
- {bullishpy-0.55.0.dist-info → bullishpy-0.75.0.dist-info}/entry_points.txt +0 -0
- {bullishpy-0.55.0.dist-info → bullishpy-0.75.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Revision ID: cc28171c21a4
|
|
4
|
+
Revises: 260fcff7212e
|
|
5
|
+
Create Date: 2025-08-15 17:04:59.467407
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Sequence, Union
|
|
10
|
+
|
|
11
|
+
from alembic import op
|
|
12
|
+
import sqlalchemy as sa
|
|
13
|
+
from sqlalchemy.dialects import sqlite
|
|
14
|
+
|
|
15
|
+
# revision identifiers, used by Alembic.
|
|
16
|
+
revision: str = "cc28171c21a4"
|
|
17
|
+
down_revision: Union[str, None] = "260fcff7212e"
|
|
18
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
19
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def upgrade() -> None:
|
|
23
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
24
|
+
with op.batch_alter_table("analysis", schema=None) as batch_op:
|
|
25
|
+
batch_op.add_column(sa.Column("adx_14", sa.Date(), nullable=True))
|
|
26
|
+
batch_op.add_column(sa.Column("adx_14_overbought", sa.Date(), nullable=True))
|
|
27
|
+
batch_op.create_index("ix_analysis_adx_14", ["adx_14"], unique=False)
|
|
28
|
+
batch_op.create_index(
|
|
29
|
+
"ix_analysis_adx_14_overbought", ["adx_14_overbought"], unique=False
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# ### end Alembic commands ###
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def downgrade() -> None:
|
|
36
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
37
|
+
with op.batch_alter_table("analysis", schema=None) as batch_op:
|
|
38
|
+
batch_op.drop_index("ix_analysis_adx_14_overbought")
|
|
39
|
+
batch_op.drop_index("ix_analysis_adx_14")
|
|
40
|
+
batch_op.drop_column("adx_14_overbought")
|
|
41
|
+
batch_op.drop_column("adx_14")
|
|
42
|
+
|
|
43
|
+
# ### end Alembic commands ###
|
bullish/database/crud.py
CHANGED
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
from datetime import date
|
|
4
4
|
from functools import cached_property
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import TYPE_CHECKING, Any, List, Optional
|
|
6
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Dict
|
|
7
7
|
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from bearish.database.crud import BearishDb # type: ignore
|
|
@@ -22,6 +22,7 @@ from bullish.analysis.constants import Industry, IndustryGroup, Sector, Country
|
|
|
22
22
|
from bullish.analysis.filter import FilteredResults
|
|
23
23
|
from bullish.analysis.indicators import SignalSeries
|
|
24
24
|
from bullish.analysis.industry_views import Type, IndustryView
|
|
25
|
+
|
|
25
26
|
from bullish.database.schemas import (
|
|
26
27
|
AnalysisORM,
|
|
27
28
|
JobTrackerORM,
|
|
@@ -29,6 +30,7 @@ from bullish.database.schemas import (
|
|
|
29
30
|
IndustryViewORM,
|
|
30
31
|
SignalSeriesORM,
|
|
31
32
|
BacktestResultORM,
|
|
33
|
+
OpenAINewsORM,
|
|
32
34
|
)
|
|
33
35
|
from bullish.database.scripts.upgrade import upgrade
|
|
34
36
|
from bullish.exceptions import DatabaseFileNotFoundError
|
|
@@ -38,6 +40,7 @@ from tickermood.database.scripts.upgrade import upgrade as tickermood_upgrade #
|
|
|
38
40
|
|
|
39
41
|
if TYPE_CHECKING:
|
|
40
42
|
from bullish.analysis.backtest import BacktestResult, BacktestResultQuery
|
|
43
|
+
from bullish.analysis.openai import OpenAINews
|
|
41
44
|
|
|
42
45
|
logger = logging.getLogger(__name__)
|
|
43
46
|
|
|
@@ -71,7 +74,11 @@ class BullishDb(BearishDb, BullishDbBase): # type: ignore
|
|
|
71
74
|
logger.info(
|
|
72
75
|
"Running tickermood upgrade to create the subject table in the database."
|
|
73
76
|
)
|
|
74
|
-
|
|
77
|
+
try:
|
|
78
|
+
tickermood_upgrade(database_url=database_url, no_migration=True)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.error(f"failed to update database: {e}")
|
|
81
|
+
print(f"failed to update database: {e}")
|
|
75
82
|
return engine
|
|
76
83
|
|
|
77
84
|
def model_post_init(self, __context: Any) -> None:
|
|
@@ -358,11 +365,53 @@ class BullishDb(BearishDb, BullishDbBase): # type: ignore
|
|
|
358
365
|
LIMIT 1
|
|
359
366
|
"""
|
|
360
367
|
)
|
|
368
|
+
sql_oai = text(
|
|
369
|
+
"""
|
|
370
|
+
SELECT *
|
|
371
|
+
FROM openai
|
|
372
|
+
WHERE symbol = :symbol
|
|
373
|
+
ORDER BY news_date DESC
|
|
374
|
+
LIMIT 1
|
|
375
|
+
"""
|
|
376
|
+
)
|
|
361
377
|
|
|
362
378
|
with Session(self._engine) as session:
|
|
363
379
|
row = session.execute(sql, {"symbol": symbol}).mappings().one_or_none()
|
|
380
|
+
row_oai = (
|
|
381
|
+
session.execute(sql_oai, {"symbol": symbol}).mappings().one_or_none()
|
|
382
|
+
)
|
|
383
|
+
row_dict = {}
|
|
364
384
|
if row:
|
|
365
385
|
row_dict = dict(row)
|
|
366
386
|
row_dict = row_dict | {"news_date": row_dict["date"]}
|
|
367
|
-
|
|
368
|
-
|
|
387
|
+
if row_oai:
|
|
388
|
+
row_dict_oai = dict(row_oai)
|
|
389
|
+
row_dict = row_dict | {
|
|
390
|
+
"oai_news_date": row_dict_oai.get("news_date"),
|
|
391
|
+
"oai_recent_news": row_dict_oai.get("recent_news"),
|
|
392
|
+
"oai_recommendation": row_dict_oai.get("recommendation"),
|
|
393
|
+
"oai_explanation": row_dict_oai.get("explanation"),
|
|
394
|
+
"oai_high_price_target": row_dict_oai.get("high_price_target"),
|
|
395
|
+
"oai_low_price_target": row_dict_oai.get("low_price_target"),
|
|
396
|
+
"oai_moat": row_dict_oai.get("moat"),
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return SubjectAnalysis.model_validate(row_dict)
|
|
400
|
+
|
|
401
|
+
def write_many_openai_news(self, openai_news: List["OpenAINews"]) -> None:
|
|
402
|
+
with Session(self._engine) as session:
|
|
403
|
+
stmt = (
|
|
404
|
+
insert(OpenAINewsORM)
|
|
405
|
+
.prefix_with("OR REPLACE")
|
|
406
|
+
.values([a.model_dump() for a in openai_news])
|
|
407
|
+
)
|
|
408
|
+
session.exec(stmt) # type: ignore
|
|
409
|
+
session.commit()
|
|
410
|
+
|
|
411
|
+
def update_analysis(self, symbol: str, fields: Dict[str, Any]) -> None:
|
|
412
|
+
with Session(self._engine) as session:
|
|
413
|
+
stmt = (
|
|
414
|
+
update(AnalysisORM).where(AnalysisORM.symbol == symbol).values(**fields) # type: ignore
|
|
415
|
+
)
|
|
416
|
+
session.exec(stmt) # type: ignore
|
|
417
|
+
session.commit()
|
bullish/database/schemas.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import date
|
|
1
2
|
from typing import Dict, Any, List, Optional
|
|
2
3
|
|
|
3
4
|
from sqlmodel import Field, SQLModel
|
|
@@ -7,6 +8,7 @@ from bullish.analysis.backtest import BacktestResult
|
|
|
7
8
|
from bullish.analysis.filter import FilteredResults
|
|
8
9
|
from bullish.analysis.indicators import SignalSeries
|
|
9
10
|
from bullish.analysis.industry_views import IndustryView
|
|
11
|
+
from bullish.analysis.openai import OpenAINews
|
|
10
12
|
|
|
11
13
|
from bullish.jobs.models import JobTracker
|
|
12
14
|
from sqlalchemy import Index
|
|
@@ -22,6 +24,13 @@ dynamic_indexes = tuple(
|
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
class OpenAINewsORM(SQLModel, OpenAINews, table=True):
|
|
28
|
+
__tablename__ = "openai"
|
|
29
|
+
__table_args__ = {"extend_existing": True} # noqa:RUF012
|
|
30
|
+
symbol: str = Field(primary_key=True)
|
|
31
|
+
news_date: date = Field(primary_key=True)
|
|
32
|
+
|
|
33
|
+
|
|
25
34
|
class AnalysisORM(BaseTable, Analysis, table=True):
|
|
26
35
|
__tablename__ = "analysis"
|
|
27
36
|
__table_args__ = {"extend_existing": True} # noqa:RUF012
|
bullish/figures/figures.py
CHANGED
|
@@ -5,7 +5,10 @@ import pandas as pd
|
|
|
5
5
|
import plotly.graph_objects as go
|
|
6
6
|
from plotly.subplots import make_subplots
|
|
7
7
|
|
|
8
|
-
from bullish.analysis.functions import
|
|
8
|
+
from bullish.analysis.functions import (
|
|
9
|
+
add_indicators,
|
|
10
|
+
support_resistance,
|
|
11
|
+
)
|
|
9
12
|
from datetime import date
|
|
10
13
|
|
|
11
14
|
|
|
@@ -17,6 +20,8 @@ def plot(
|
|
|
17
20
|
industry_data: Optional[pd.DataFrame] = None,
|
|
18
21
|
) -> go.Figure:
|
|
19
22
|
data = add_indicators(data)
|
|
23
|
+
supports = support_resistance(data)
|
|
24
|
+
|
|
20
25
|
fig = make_subplots(
|
|
21
26
|
rows=7,
|
|
22
27
|
cols=1,
|
|
@@ -36,8 +41,8 @@ def plot(
|
|
|
36
41
|
f"RSI ({symbol} [{name}])",
|
|
37
42
|
f"MACD ({symbol} [{name}])",
|
|
38
43
|
f"ADX ({symbol} [{name}])",
|
|
39
|
-
f"
|
|
40
|
-
f"
|
|
44
|
+
f"ATR ({symbol} [{name}])",
|
|
45
|
+
f"ADOSC ({symbol} [{name}])",
|
|
41
46
|
),
|
|
42
47
|
)
|
|
43
48
|
# Row 1: Candlestick + SMAs
|
|
@@ -114,28 +119,15 @@ def plot(
|
|
|
114
119
|
col=1,
|
|
115
120
|
)
|
|
116
121
|
fig.add_trace(
|
|
117
|
-
go.Scatter(x=data.index, y=data.
|
|
122
|
+
go.Scatter(x=data.index, y=data.ATR, name="ATR", mode="lines"),
|
|
118
123
|
row=6,
|
|
119
124
|
col=1,
|
|
120
125
|
)
|
|
121
126
|
fig.add_trace(
|
|
122
127
|
go.Scatter(x=data.index, y=data.ADOSC, name="ADOSC", mode="lines"),
|
|
123
|
-
row=
|
|
128
|
+
row=7,
|
|
124
129
|
col=1,
|
|
125
130
|
)
|
|
126
|
-
if industry_data is not None and not industry_data.empty:
|
|
127
|
-
for c in industry_data.columns:
|
|
128
|
-
fig.add_trace(
|
|
129
|
-
go.Scatter(
|
|
130
|
-
x=industry_data.index,
|
|
131
|
-
y=industry_data[c],
|
|
132
|
-
name=c,
|
|
133
|
-
mode="lines",
|
|
134
|
-
opacity=0.5 if c != "symbol" else 1.0,
|
|
135
|
-
),
|
|
136
|
-
row=7,
|
|
137
|
-
col=1,
|
|
138
|
-
)
|
|
139
131
|
|
|
140
132
|
if dates is not None and dates:
|
|
141
133
|
for date in dates:
|
|
@@ -166,5 +158,23 @@ def plot(
|
|
|
166
158
|
fig.add_hline(y=70, line_dash="dash", line_color="red", row=3, col=1)
|
|
167
159
|
fig.add_hline(y=30, line_dash="dash", line_color="green", row=3, col=1)
|
|
168
160
|
fig.add_hline(y=25, line_dash="dash", line_color="red", row=5, col=1)
|
|
161
|
+
fig.add_hline(
|
|
162
|
+
y=supports.support.value,
|
|
163
|
+
line_dash="dash",
|
|
164
|
+
line_color="rgba(26, 188, 156, 1)", # teal, fully opaque
|
|
165
|
+
annotation_text=f"Support ({supports.support.value:.2f})",
|
|
166
|
+
line_width=0.75,
|
|
167
|
+
row=1,
|
|
168
|
+
col=1,
|
|
169
|
+
)
|
|
170
|
+
fig.add_hline(
|
|
171
|
+
y=supports.resistance.value,
|
|
172
|
+
line_dash="dash",
|
|
173
|
+
line_color="rgba(230, 126, 34, 1)", # orange, fully opaque
|
|
174
|
+
annotation_text=f"Resistance ({supports.resistance.value:.2f})",
|
|
175
|
+
line_width=0.75,
|
|
176
|
+
row=1,
|
|
177
|
+
col=1,
|
|
178
|
+
)
|
|
169
179
|
|
|
170
180
|
return fig
|
bullish/interface/interface.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import logging
|
|
3
3
|
from datetime import date
|
|
4
|
-
from typing import List, Optional
|
|
4
|
+
from typing import List, Optional, Dict, Any
|
|
5
5
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
from bearish.interface.interface import BearishDbBase # type: ignore
|
|
@@ -15,6 +15,7 @@ from bullish.analysis.constants import Industry, Sector, IndustryGroup, Country
|
|
|
15
15
|
from bullish.analysis.filter import FilterQuery, FilteredResults
|
|
16
16
|
from bullish.analysis.indicators import SignalSeries
|
|
17
17
|
from bullish.analysis.industry_views import Type, IndustryView
|
|
18
|
+
from bullish.analysis.openai import OpenAINews
|
|
18
19
|
from bullish.jobs.models import JobTracker, JobTrackerStatus, add_icons
|
|
19
20
|
|
|
20
21
|
logger = logging.getLogger(__name__)
|
|
@@ -155,3 +156,8 @@ class BullishDbBase(BearishDbBase): # type: ignore
|
|
|
155
156
|
|
|
156
157
|
@abc.abstractmethod
|
|
157
158
|
def read_subject(self, symbol: str) -> Optional[SubjectAnalysis]: ...
|
|
159
|
+
@abc.abstractmethod
|
|
160
|
+
def write_many_openai_news(self, openai_news: List[OpenAINews]) -> None: ...
|
|
161
|
+
|
|
162
|
+
@abc.abstractmethod
|
|
163
|
+
def update_analysis(self, symbol: str, fields: Dict[str, Any]) -> None: ...
|
bullish/jobs/tasks.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import Optional, Any, Callable, List
|
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
from bearish.main import Bearish # type: ignore
|
|
7
|
+
from bearish.models.sec.sec import Secs # type: ignore
|
|
7
8
|
from tickermood.main import get_news # type: ignore
|
|
8
9
|
from tickermood.types import DatabaseConfig # type: ignore
|
|
9
10
|
|
|
@@ -15,6 +16,7 @@ from .models import JobTrackerStatus, JobTracker, JobType
|
|
|
15
16
|
from ..analysis.analysis import run_analysis, run_signal_series_analysis
|
|
16
17
|
from ..analysis.backtest import run_many_tests, BackTestConfig
|
|
17
18
|
from ..analysis.industry_views import compute_industry_view
|
|
19
|
+
from ..analysis.openai import get_open_ai_news
|
|
18
20
|
from ..analysis.predefined_filters import predefined_filters, load_custom_filters
|
|
19
21
|
from ..database.crud import BullishDb
|
|
20
22
|
from bullish.analysis.filter import FilterUpdate
|
|
@@ -83,6 +85,9 @@ def _base_update(
|
|
|
83
85
|
series_length=update_query.window_size,
|
|
84
86
|
delay=update_query.data_age_in_days,
|
|
85
87
|
)
|
|
88
|
+
bearish.get_prices_index(series_length=update_query.window_size)
|
|
89
|
+
Secs.upload(bearish._bearish_db)
|
|
90
|
+
Secs.update_values(bearish._secs_db)
|
|
86
91
|
if update_query.update_financials:
|
|
87
92
|
bearish.update_financials()
|
|
88
93
|
bullish_db = BullishDb(database_path=database_path)
|
|
@@ -125,6 +130,21 @@ def cron_update(
|
|
|
125
130
|
)
|
|
126
131
|
|
|
127
132
|
|
|
133
|
+
@huey.periodic_task(crontab(day_of_week=0, hour=9, minute=0), context=True) # type: ignore
|
|
134
|
+
def cron_financial_update(
|
|
135
|
+
task: Optional[Task] = None,
|
|
136
|
+
) -> None:
|
|
137
|
+
database = DataBaseSingleTon()
|
|
138
|
+
if database.valid():
|
|
139
|
+
job_tracker(_base_update)(
|
|
140
|
+
database.path,
|
|
141
|
+
"Update data",
|
|
142
|
+
[],
|
|
143
|
+
FilterUpdate(update_financials=True),
|
|
144
|
+
task=task,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
128
148
|
@huey.task(context=True) # type: ignore
|
|
129
149
|
@job_tracker
|
|
130
150
|
def analysis(
|
|
@@ -171,16 +191,31 @@ def news(
|
|
|
171
191
|
headless: bool = True,
|
|
172
192
|
task: Optional[Task] = None,
|
|
173
193
|
) -> None:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
194
|
+
bullish_db = BullishDb(database_path=database_path)
|
|
195
|
+
if get_open_ai_news(bullish_db, symbols):
|
|
196
|
+
for symbol in symbols:
|
|
197
|
+
subject = bullish_db.read_subject(symbol)
|
|
198
|
+
if subject:
|
|
199
|
+
logger.debug(
|
|
200
|
+
f"extracting news for {symbol} subject: {subject.model_dump()}"
|
|
201
|
+
)
|
|
202
|
+
try:
|
|
203
|
+
bullish_db.update_analysis(
|
|
204
|
+
symbol,
|
|
205
|
+
subject.model_dump(
|
|
206
|
+
exclude_none=True,
|
|
207
|
+
exclude_unset=True,
|
|
208
|
+
exclude_defaults=True,
|
|
209
|
+
exclude={"symbol"},
|
|
210
|
+
),
|
|
211
|
+
)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.error(f"failed to extract news for {symbol}: {e}")
|
|
214
|
+
print(f"failed to extract news for {symbol}: {e}")
|
|
215
|
+
continue
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@huey.periodic_task(crontab(minute="0", hour="8"), context=True) # type: ignore
|
|
184
219
|
def cron_news(
|
|
185
220
|
task: Optional[Task] = None,
|
|
186
221
|
) -> None:
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: bullishpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.75.0
|
|
4
4
|
Summary:
|
|
5
|
+
License-File: LICENSE
|
|
5
6
|
Author: aan
|
|
6
7
|
Author-email: andoludovic.andriamamonjy@gmail.com
|
|
7
8
|
Requires-Python: >=3.12,<3.13
|
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
|
9
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
-
Requires-Dist: bearishpy (>=0.
|
|
11
|
+
Requires-Dist: bearishpy (>=0.35.0,<0.36.0)
|
|
11
12
|
Requires-Dist: click (>=7.0,<=8.1)
|
|
12
13
|
Requires-Dist: huey (>=2.5.3,<3.0.0)
|
|
13
14
|
Requires-Dist: joblib (>=1.5.1,<2.0.0)
|
|
14
|
-
Requires-Dist:
|
|
15
|
+
Requires-Dist: mysec (>=0.3.0,<0.4.0)
|
|
16
|
+
Requires-Dist: pandas-ta (>=0.4.71b0,<0.5.0)
|
|
15
17
|
Requires-Dist: plotly (>=4.12.0,<6.0.0)
|
|
16
18
|
Requires-Dist: streamlit (>=1.45.1,<2.0.0)
|
|
17
19
|
Requires-Dist: streamlit-file-browser (>=3.2.22,<4.0.0)
|
|
18
20
|
Requires-Dist: streamlit-pydantic (>=v0.6.1-rc.3,<0.7.0)
|
|
19
21
|
Requires-Dist: ta-lib (>=0.6.4,<0.7.0)
|
|
20
|
-
Requires-Dist: tickermood (>=0.
|
|
22
|
+
Requires-Dist: tickermood (>=0.29.0,<0.30.0)
|
|
21
23
|
Requires-Dist: vectorbt (>=0.28.0,<0.29.0)
|
|
22
24
|
Description-Content-Type: text/markdown
|
|
23
25
|
|
|
@@ -51,7 +53,7 @@ See the [TA-Lib installation guide](https://ta-lib.org/) for instructions.
|
|
|
51
53
|
|
|
52
54
|
## Installation
|
|
53
55
|
```bash
|
|
54
|
-
pip install
|
|
56
|
+
pip install bullishpy
|
|
55
57
|
```
|
|
56
58
|
|
|
57
59
|
---
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
bullish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
bullish/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
bullish/analysis/analysis.py,sha256=
|
|
3
|
+
bullish/analysis/analysis.py,sha256=3lZSLpTe4lFBGNrCpXmYBZhwD7o0rXSbQEkLpxJLylA,25130
|
|
4
4
|
bullish/analysis/backtest.py,sha256=x91ek5kOzJHvYq0TmJh1Q8wBDDduIaieE0zDaoZFXew,14325
|
|
5
|
-
bullish/analysis/constants.py,sha256=
|
|
6
|
-
bullish/analysis/filter.py,sha256=
|
|
7
|
-
bullish/analysis/functions.py,sha256=
|
|
8
|
-
bullish/analysis/indicators.py,sha256=
|
|
5
|
+
bullish/analysis/constants.py,sha256=j3vQwjGhY-4dEEV-TkeKMDUTo2GM7M97Hcpi19LDcFQ,11458
|
|
6
|
+
bullish/analysis/filter.py,sha256=VvQALnYNyYylXkorYR3oGhsF4L_sAUSE7-aop4Trp9o,9326
|
|
7
|
+
bullish/analysis/functions.py,sha256=jw1Tc-YtoyobYhC6AWJH-xXgaczwDZMTfQIES6Y_8qM,15780
|
|
8
|
+
bullish/analysis/indicators.py,sha256=CcDu8mu1jOOS5-3gNHYA9qDA3Ua-6PGUyoio2bDIe48,28435
|
|
9
9
|
bullish/analysis/industry_views.py,sha256=-B4CCAYz2arGQtWTXLLMpox0loO_MGdVQd2ycCRMOQQ,6799
|
|
10
|
-
bullish/analysis/
|
|
10
|
+
bullish/analysis/openai.py,sha256=Fw7A8lFMgSEQFA48Q9GjVpEC3oiBgSHUFi7YO5rzhAc,3444
|
|
11
|
+
bullish/analysis/predefined_filters.py,sha256=E65qrTSaDFuUxoaeZ8D72K5AobumobpQdpcTIF308D4,14053
|
|
11
12
|
bullish/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
bullish/app/app.py,sha256=
|
|
13
|
+
bullish/app/app.py,sha256=FLWwhjGwMVXYfA9EI5RUeQRQGf9Qu7up0ypJgS4FTFE,17367
|
|
13
14
|
bullish/cli.py,sha256=yYqiEQAvOIQ-pTn77RPuE449gwaEGBeQwNHHAJ5yQDM,2739
|
|
14
15
|
bullish/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
16
|
bullish/database/alembic/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
|
|
@@ -27,37 +28,42 @@ bullish/database/alembic/versions/49c83f9eb5ac_.py,sha256=kCBItp7KmqpJ03roy5ikQj
|
|
|
27
28
|
bullish/database/alembic/versions/4b0a2f40b7d3_.py,sha256=G0K7w7pOPYjPZkXTB8LWhxoxuWBPcPwOfnubTBtdeEY,1827
|
|
28
29
|
bullish/database/alembic/versions/4ee82b171449_.py,sha256=QtPy5VyZPyZxS7MVkk_wGi3C44PVDoHyJ-9m9fWdqqc,1047
|
|
29
30
|
bullish/database/alembic/versions/5b10ee7604c1_.py,sha256=YlqaagPasR3RKASv7acME1jPS8p26VoTE2BvpOwdCpY,1463
|
|
31
|
+
bullish/database/alembic/versions/65662e214031_.py,sha256=Yq3lOW6liYTYiBaPRcFqVjn3k5z1mWIUXT17bv9ZroY,1596
|
|
32
|
+
bullish/database/alembic/versions/660897c02c00_.py,sha256=Sc_4uJAGheebijw3WzFNHclcWz0YF8vaZKEmVBwglDc,1033
|
|
30
33
|
bullish/database/alembic/versions/6d252e23f543_.py,sha256=izF-ejdXk733INkAokGqjA2U_M0_c1f_ruihZ-cgP7s,1525
|
|
31
34
|
bullish/database/alembic/versions/73564b60fe24_.py,sha256=MTlDRDNHj3E9gK7IMeAzv2UxxxYtWiu3gI_9xTLE-wg,1008
|
|
32
35
|
bullish/database/alembic/versions/79bc71ec6f9e_.py,sha256=4nShut2NEd1F3piSckIIBtke0GEsFAxYw5TZl5YYRzc,1140
|
|
33
36
|
bullish/database/alembic/versions/ae444f338124_.py,sha256=u8RphcniLCQce-HvN666QgCJpLsv6A91-a4R-Nif4bU,3672
|
|
37
|
+
bullish/database/alembic/versions/b36c310f49ec_.py,sha256=L0B3wyo9i0R14_H5fcDAxAm_5P1zIFsHUY888Do-pbI,1379
|
|
34
38
|
bullish/database/alembic/versions/b76079e9845f_.py,sha256=W8eeTABjI9tT1dp3hlK7g7tiKqDhmA8AoUX9Sw-ykLI,1165
|
|
35
39
|
bullish/database/alembic/versions/bf6b86dd5463_.py,sha256=fKB8knCprGmiL6AEyFdhybVmB7QX_W4MPFF9sPzUrSM,1094
|
|
40
|
+
bullish/database/alembic/versions/c828e29e1105_.py,sha256=rO9qwNay8HohSVHIJgYq7VWhtgn-jpF10h98WCu-wjU,3052
|
|
41
|
+
bullish/database/alembic/versions/cc28171c21a4_.py,sha256=ZsHFzqo6cfTXDodxaXRzkoKl0zK2TR15nD4SJeDlRi0,1401
|
|
36
42
|
bullish/database/alembic/versions/d0e58e050845_.py,sha256=x_LS3J27FNyy_WD99uvZzNehly-jpgn9abOYN-VjjZc,1164
|
|
37
43
|
bullish/database/alembic/versions/d663166c531d_.py,sha256=U92l6QXqPniAYrPeu2Bt77ReDbXveLj4aGXtgd806JY,1915
|
|
38
44
|
bullish/database/alembic/versions/ec25c8fa449f_.py,sha256=8Yts74KEjK4jg20zIo90_0atw-sOBuE3hgCKl-rfS5E,2271
|
|
39
45
|
bullish/database/alembic/versions/ee5baabb35f8_.py,sha256=nBMEY-_C8AsSXVPyaDdUkwrFFo2gxShzJhmrjejDwtc,1632
|
|
40
46
|
bullish/database/alembic/versions/fc191121f522_.py,sha256=0sstF6TpAJ09-Mt-Vek9SdSWksvi4C58a5D92rBtuY8,1894
|
|
41
47
|
bullish/database/alembic/versions/ff0cc4ba40ec_.py,sha256=74lxga54ig_LoNZYK9toJL9iRwGbNRezh1zvO1YI40U,2719
|
|
42
|
-
bullish/database/crud.py,sha256
|
|
43
|
-
bullish/database/schemas.py,sha256=
|
|
48
|
+
bullish/database/crud.py,sha256=-pncRg_YA5y2wE2HELJHiGbeTzmaGF7LjMC8be10qwA,16123
|
|
49
|
+
bullish/database/schemas.py,sha256=HudFJ9lsIkVaEYjQUWammrsDnYSmEe4hOCbim3dN_4A,3946
|
|
44
50
|
bullish/database/scripts/create_revision.py,sha256=rggIf-3koPqJNth8FIg89EOfnIM7a9QrvL8X7UJsP0g,628
|
|
45
51
|
bullish/database/scripts/stamp.py,sha256=PWgVUEBumjNUMjTnGw46qmU3p221LeN-KspnW_gFuu4,839
|
|
46
52
|
bullish/database/scripts/upgrade.py,sha256=-Gz7aFNPEt9y9e1kltqXE76-j_8QeNtet_VlwY5AWjo,806
|
|
47
53
|
bullish/database/settings.py,sha256=nMudufmF7iC_62_PHrGSMjlqDLN2I0qTbtz9JKZHSko,164
|
|
48
54
|
bullish/exceptions.py,sha256=4z_i-dD-CDz1bkGmZH9DOf1L_awlCPCgdUDPF7dhWAI,106
|
|
49
55
|
bullish/figures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
-
bullish/figures/figures.py,sha256=
|
|
56
|
+
bullish/figures/figures.py,sha256=aeMAZGr8HkcF6CIf8ed4cnxJ1YkOY2-euP5egwm0ELk,4750
|
|
51
57
|
bullish/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
-
bullish/interface/interface.py,sha256=
|
|
58
|
+
bullish/interface/interface.py,sha256=6uZAY19WNtDRKdOitqzqMEo6JTep2M3HC8iFUKYntHA,5518
|
|
53
59
|
bullish/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
60
|
bullish/jobs/app.py,sha256=5MJ5KXUo7JSNAvOPgkpIMasD11VTrjQvGzM7vmCY65E,77
|
|
55
61
|
bullish/jobs/models.py,sha256=rBXxtGFBpgZprrxq5_X2Df-bh8BLYEfw-VLMRucrqa8,784
|
|
56
|
-
bullish/jobs/tasks.py,sha256=
|
|
62
|
+
bullish/jobs/tasks.py,sha256=PBi5kzXgX800pmBtwypHJoKIW0V3vYIPf4EDh-FJ6os,7563
|
|
57
63
|
bullish/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
64
|
bullish/utils/checks.py,sha256=g-5QXNWNe1_BwHKrc2PtvPiLraL0tqGgxnzG7u-Wkgo,2189
|
|
59
|
-
bullishpy-0.
|
|
60
|
-
bullishpy-0.
|
|
61
|
-
bullishpy-0.
|
|
62
|
-
bullishpy-0.
|
|
63
|
-
bullishpy-0.
|
|
65
|
+
bullishpy-0.75.0.dist-info/METADATA,sha256=1uDs1Zxem_Xo3ZsJBulRJeOEBl3WlyWT1bNDVekid7I,3069
|
|
66
|
+
bullishpy-0.75.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
67
|
+
bullishpy-0.75.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
|
|
68
|
+
bullishpy-0.75.0.dist-info/licenses/LICENSE,sha256=nYb7AJFegu6ndlQhbbk54MjT-GH-0x9RF6Ls-ggJ_g4,1075
|
|
69
|
+
bullishpy-0.75.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|