bullishpy 0.13.0__py3-none-any.whl → 0.14.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/database/crud.py CHANGED
@@ -3,19 +3,27 @@ import logging
3
3
  from datetime import date
4
4
  from functools import cached_property
5
5
  from pathlib import Path
6
- from sqlite3 import OperationalError
7
6
  from typing import TYPE_CHECKING, Any, List, Optional
8
7
 
9
8
  import pandas as pd
10
9
  from bearish.database.crud import BearishDb # type: ignore
11
10
  from bearish.models.base import Ticker # type: ignore
12
- from bearish.database.schemas import EarningsDateORM # type: ignore
11
+ from bearish.database.schemas import EarningsDateORM, EquityORM # type: ignore
12
+ from bearish.types import Sources # type: ignore
13
13
  from pydantic import ConfigDict
14
14
  from sqlalchemy import Engine, create_engine, insert, delete, update
15
15
  from sqlmodel import Session, select
16
16
 
17
17
  from bullish.analysis.analysis import Analysis
18
- from bullish.database.schemas import AnalysisORM, JobTrackerORM, FilteredResultsORM
18
+ from bullish.analysis.constants import Industry, IndustryGroup, Sector, Country
19
+ from bullish.analysis.industry_views import Type, IndustryView
20
+
21
+ from bullish.database.schemas import (
22
+ AnalysisORM,
23
+ JobTrackerORM,
24
+ FilteredResultsORM,
25
+ IndustryViewORM,
26
+ )
19
27
  from bullish.database.scripts.upgrade import upgrade
20
28
  from bullish.exceptions import DatabaseFileNotFoundError
21
29
  from bullish.analysis.filter import FilteredResults
@@ -45,7 +53,7 @@ class BullishDb(BearishDb, BullishDbBase): # type: ignore
45
53
  database_url = f"sqlite:///{Path(self.database_path)}"
46
54
  try:
47
55
  upgrade(self.database_path)
48
- except OperationalError as e:
56
+ except Exception as e:
49
57
  logger.warning(
50
58
  f"Failed to upgrade the database at {self.database_path}. "
51
59
  f"Reason: {e}"
@@ -193,3 +201,63 @@ class BullishDb(BearishDb, BullishDbBase): # type: ignore
193
201
  select(EarningsDateORM.date).where(EarningsDateORM.symbol == symbol)
194
202
  )
195
203
  ]
204
+
205
+ def read_industry_symbols(
206
+ self, industries: List[Industry], country: Country, source: Sources = "Yfinance"
207
+ ) -> List[str]:
208
+ with Session(self._engine) as session:
209
+ stmt = select(EquityORM.symbol).where(
210
+ EquityORM.industry.in_(industries),
211
+ EquityORM.source == source,
212
+ EquityORM.country == country,
213
+ )
214
+ result = session.exec(stmt).all()
215
+ return list(result)
216
+
217
+ def read_industry_group_symbols(
218
+ self,
219
+ industry_groups: List[IndustryGroup],
220
+ country: Country,
221
+ source: Sources = "Yfinance",
222
+ ) -> List[str]:
223
+ with Session(self._engine) as session:
224
+ stmt = select(EquityORM.symbol).where(
225
+ EquityORM.industry_group.in_(industry_groups),
226
+ EquityORM.source == source,
227
+ EquityORM.country == country,
228
+ )
229
+ result = session.exec(stmt).all()
230
+ return list(result)
231
+
232
+ def read_sector_symbols(
233
+ self, sectors: List[Sector], country: Country, source: Sources = "Yfinance"
234
+ ) -> List[str]:
235
+ with Session(self._engine) as session:
236
+ stmt = select(EquityORM.symbol).where(
237
+ EquityORM.sector.in_(sectors),
238
+ EquityORM.source == source,
239
+ EquityORM.country == country,
240
+ )
241
+ result = session.exec(stmt).all()
242
+ return list(result)
243
+
244
+ def write_returns(self, industry_returns: List[IndustryView]) -> None:
245
+ with Session(self._engine) as session:
246
+ stmt = (
247
+ insert(IndustryViewORM)
248
+ .prefix_with("OR REPLACE")
249
+ .values([a.model_dump() for a in industry_returns])
250
+ )
251
+ session.exec(stmt) # type: ignore
252
+ session.commit()
253
+
254
+ def read_returns(
255
+ self, type: Type, industry: Industry, country: Country
256
+ ) -> List[IndustryView]:
257
+ with Session(self._engine) as session:
258
+ stmt = select(IndustryViewORM).where(
259
+ IndustryViewORM.industry == industry,
260
+ IndustryViewORM.country == country,
261
+ )
262
+ result = session.exec(stmt).all()
263
+ return [IndustryView.model_validate(r) for r in result]
@@ -4,6 +4,8 @@ from sqlmodel import Field, SQLModel
4
4
  from sqlalchemy import Column, JSON
5
5
  from bullish.analysis.analysis import Analysis
6
6
  from bullish.analysis.filter import FilteredResults
7
+ from bullish.analysis.industry_views import IndustryView
8
+
7
9
  from bullish.jobs.models import JobTracker
8
10
  from sqlalchemy import Index
9
11
 
@@ -44,3 +46,18 @@ class FilteredResultsORM(SQLModel, FilteredResults, table=True):
44
46
  name: str = Field(primary_key=True)
45
47
  symbols: list[str] = Field(sa_column=Column(JSON))
46
48
  filter_query: Dict[str, Any] = Field(sa_column=Column(JSON)) # type: ignore
49
+
50
+
51
+ class IndustryViewORM(SQLModel, IndustryView, table=True):
52
+ __tablename__ = "industryview"
53
+ __table_args__ = {"extend_existing": True} # noqa:RUF012
54
+ date: str = Field(primary_key=True) # type: ignore
55
+ created_at: str = Field(default=None, nullable=True) # type: ignore
56
+ simple_return: float | None = Field(default=None, nullable=True) # type: ignore
57
+ log_return: float | None = Field(default=None, nullable=True) # type: ignore
58
+ normalized_close: float | None = Field(default=None, nullable=True) # type: ignore
59
+ country: str = Field(primary_key=True) # type: ignore
60
+ industry: str = Field(primary_key=True) # type: ignore
61
+ industry_group: str | None = Field(default=None, nullable=True) # type: ignore
62
+ sector: str | None = Field(default=None, nullable=True) # type: ignore
63
+ type: str = Field(primary_key=True) # type: ignore
@@ -14,6 +14,7 @@ def plot(
14
14
  symbol: str,
15
15
  name: Optional[str] = None,
16
16
  dates: Optional[List[date]] = None,
17
+ industry_data: Optional[pd.DataFrame] = None,
17
18
  ) -> go.Figure:
18
19
  data = add_indicators(data)
19
20
  fig = make_subplots(
@@ -122,11 +123,33 @@ def plot(
122
123
  row=6,
123
124
  col=1,
124
125
  )
125
- fig.add_trace(
126
- go.Scatter(x=data.index, y=data.ATR, name="ATR", mode="lines"),
127
- row=7,
128
- col=1,
129
- )
126
+ if (
127
+ industry_data is not None
128
+ and not industry_data.empty
129
+ and "symbol" in industry_data.columns
130
+ and "industry" in industry_data.columns
131
+ ):
132
+ fig.add_trace(
133
+ go.Scatter(
134
+ x=industry_data.index,
135
+ y=industry_data.symbol,
136
+ name="Symbol",
137
+ mode="lines",
138
+ ),
139
+ row=7,
140
+ col=1,
141
+ )
142
+ fig.add_trace(
143
+ go.Scatter(
144
+ x=industry_data.index,
145
+ y=industry_data.industry,
146
+ name="Industry",
147
+ mode="lines",
148
+ opacity=0.5,
149
+ ),
150
+ row=7,
151
+ col=1,
152
+ )
130
153
  if dates is not None and dates:
131
154
  for date in dates:
132
155
  if (
@@ -6,10 +6,13 @@ from typing import List, Optional
6
6
  import pandas as pd
7
7
  from bearish.interface.interface import BearishDbBase # type: ignore
8
8
  from bearish.models.base import Ticker # type: ignore
9
+ from bearish.types import Sources # type: ignore
9
10
 
10
11
 
11
12
  from bullish.analysis.analysis import Analysis, AnalysisView
13
+ from bullish.analysis.constants import Industry, Sector, IndustryGroup, Country
12
14
  from bullish.analysis.filter import FilterQuery, FilteredResults
15
+ from bullish.analysis.industry_views import Type, IndustryView
13
16
  from bullish.jobs.models import JobTracker, JobTrackerStatus, add_icons
14
17
 
15
18
  logger = logging.getLogger(__name__)
@@ -96,3 +99,29 @@ class BullishDbBase(BearishDbBase): # type: ignore
96
99
 
97
100
  @abc.abstractmethod
98
101
  def read_dates(self, symbol: str) -> List[date]: ...
102
+
103
+ @abc.abstractmethod
104
+ def read_industry_symbols(
105
+ self, industries: List[Industry], country: Country, source: Sources = "Yfinance"
106
+ ) -> List[str]: ...
107
+
108
+ @abc.abstractmethod
109
+ def read_industry_group_symbols(
110
+ self,
111
+ industry_groups: List[IndustryGroup],
112
+ country: Country,
113
+ source: Sources = "Yfinance",
114
+ ) -> List[str]: ...
115
+
116
+ @abc.abstractmethod
117
+ def read_sector_symbols(
118
+ self, sectors: List[Sector], country: Country, source: Sources = "Yfinance"
119
+ ) -> List[str]: ...
120
+
121
+ @abc.abstractmethod
122
+ def write_returns(self, industry_returns: List[IndustryView]) -> None: ...
123
+
124
+ @abc.abstractmethod
125
+ def read_returns(
126
+ self, type: Type, industry: Industry, country: Country
127
+ ) -> List[IndustryView]: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bullishpy
3
- Version: 0.13.0
3
+ Version: 0.14.0
4
4
  Summary:
5
5
  Author: aan
6
6
  Author-email: andoludovic.andriamamonjy@gmail.com
@@ -1,12 +1,14 @@
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=v5MFGhQUpMwGAVE0dg2293ldRSgQmqy5CiF8MQFTibM,19165
4
- bullish/analysis/filter.py,sha256=S8TuxoTAUY0U8ARPjNHE0tSSE_ToWkfZazAgnfgswk4,18136
5
- bullish/analysis/functions.py,sha256=DYqx5ZGR-zjCwDwhDQJqRFH8LpmzvFEcfItojbIcddU,14699
6
- bullish/analysis/indicators.py,sha256=JXqXsRDn-hiXcrBqqzJ3-xxANAherwaCZy38XykjJBA,20726
7
- bullish/analysis/predefined_filters.py,sha256=MvIuGug-RWO7QtWNEtOFROf-sY8IXu444g174cE-5m0,15200
3
+ bullish/analysis/analysis.py,sha256=ZTRf7YaEnFL9HBVkamY7JXys3XJtkLGNMkU4FbkV_04,19270
4
+ bullish/analysis/constants.py,sha256=tVDPQEufH8lytMj4DdUdvXt79b7cvWaDwSUOpeqMWts,9851
5
+ bullish/analysis/filter.py,sha256=kSG6fXZrnwqE1HvKQW6O3yVNV49qhVleer9M_7BIDpg,8381
6
+ bullish/analysis/functions.py,sha256=A2eFBqNx5XohEhJFU_LvyU0_s0ozErtsiYUqVSb3Wvs,14367
7
+ bullish/analysis/indicators.py,sha256=9-768_ntZRxNgeNXj3MbRO9QCq97uYKMHQ-9hQMu7Mo,20938
8
+ bullish/analysis/industry_views.py,sha256=1B5V39Fm9rNQEsun1xrwELfOiKlGdTie0ZolS2UBh2w,6247
9
+ bullish/analysis/predefined_filters.py,sha256=28e42hGaH7Qb6SPNeH7EK9YIhjERj-qpbY-7xLahvDM,8361
8
10
  bullish/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- bullish/app/app.py,sha256=E0H78LOODl1H6s308jXpQGTUoFPoLOJkPBXOLQGLCeA,13331
11
+ bullish/app/app.py,sha256=3xSO4x3T7BnD60M-AQM6-xkRVFLCWqGJ6DWqLmKxbzw,13663
10
12
  bullish/cli.py,sha256=uYLZmGDAolZKWzduZ58bP-xul1adg0oKfeUQtZMXTvA,1958
11
13
  bullish/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
14
  bullish/database/alembic/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
@@ -14,35 +16,38 @@ bullish/database/alembic/alembic.ini,sha256=VuwqBJV5ObTyyRNrqv8Xr-TDIRfqPjP9R1mq
14
16
  bullish/database/alembic/env.py,sha256=TBsN4TyVppyc2QpWqViebd4-xxUT7Cs3GDYXQdKiAMs,2260
15
17
  bullish/database/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
16
18
  bullish/database/alembic/versions/037dbd721317_.py,sha256=U7EA4odH3t9w0-J4FmvBUt8HOuGDMn0rEAu_0vPUYaI,8595
19
+ bullish/database/alembic/versions/040b15fba458_.py,sha256=scSauB4wZe0sMFHOAMHkx-rNSF06Pn3D52QJ10PvERg,2314
17
20
  bullish/database/alembic/versions/08ac1116e055_.py,sha256=zMEiCbraMEAZItT4ibc3evAH7-7mkXpdgnZy4tPVYeg,27263
18
21
  bullish/database/alembic/versions/11d35a452b40_.py,sha256=j2PaU1RssLQ20OevGmBC7S9E9ocWiXpBue9SOS4AQoY,11521
19
22
  bullish/database/alembic/versions/17e51420e7ad_.py,sha256=xeiVIm1YUZb08opE9rocHZP1__9WQWXsKsXgeFV9cvs,2960
20
23
  bullish/database/alembic/versions/49c83f9eb5ac_.py,sha256=kCBItp7KmqpJ03roy5ikQjhefZia1oKgfZwournQDq8,3890
21
24
  bullish/database/alembic/versions/4b0a2f40b7d3_.py,sha256=G0K7w7pOPYjPZkXTB8LWhxoxuWBPcPwOfnubTBtdeEY,1827
25
+ bullish/database/alembic/versions/5b10ee7604c1_.py,sha256=YlqaagPasR3RKASv7acME1jPS8p26VoTE2BvpOwdCpY,1463
22
26
  bullish/database/alembic/versions/73564b60fe24_.py,sha256=MTlDRDNHj3E9gK7IMeAzv2UxxxYtWiu3gI_9xTLE-wg,1008
23
27
  bullish/database/alembic/versions/b76079e9845f_.py,sha256=W8eeTABjI9tT1dp3hlK7g7tiKqDhmA8AoUX9Sw-ykLI,1165
24
28
  bullish/database/alembic/versions/bf6b86dd5463_.py,sha256=fKB8knCprGmiL6AEyFdhybVmB7QX_W4MPFF9sPzUrSM,1094
25
29
  bullish/database/alembic/versions/d663166c531d_.py,sha256=U92l6QXqPniAYrPeu2Bt77ReDbXveLj4aGXtgd806JY,1915
30
+ bullish/database/alembic/versions/ec25c8fa449f_.py,sha256=8Yts74KEjK4jg20zIo90_0atw-sOBuE3hgCKl-rfS5E,2271
26
31
  bullish/database/alembic/versions/ee5baabb35f8_.py,sha256=nBMEY-_C8AsSXVPyaDdUkwrFFo2gxShzJhmrjejDwtc,1632
27
32
  bullish/database/alembic/versions/fc191121f522_.py,sha256=0sstF6TpAJ09-Mt-Vek9SdSWksvi4C58a5D92rBtuY8,1894
28
- bullish/database/crud.py,sha256=0AMrs07MMeDq5AVft_pf43KWPFOusMNzUmxuXwMX6K4,7400
29
- bullish/database/schemas.py,sha256=bU-DW49NqpBp--1VN486LUdDmLeScrI8TF69afzjoTc,1507
33
+ bullish/database/crud.py,sha256=ubRXV88GAo4prDQPylouEn8DBvoyNtM6hx12HPhD_2w,9889
34
+ bullish/database/schemas.py,sha256=gI6hWYv1C4G9xRXiNTSLxXftkgIOANDyfct2_KwSavo,2442
30
35
  bullish/database/scripts/create_revision.py,sha256=rggIf-3koPqJNth8FIg89EOfnIM7a9QrvL8X7UJsP0g,628
31
36
  bullish/database/scripts/stamp.py,sha256=PWgVUEBumjNUMjTnGw46qmU3p221LeN-KspnW_gFuu4,839
32
37
  bullish/database/scripts/upgrade.py,sha256=-Gz7aFNPEt9y9e1kltqXE76-j_8QeNtet_VlwY5AWjo,806
33
38
  bullish/database/settings.py,sha256=nMudufmF7iC_62_PHrGSMjlqDLN2I0qTbtz9JKZHSko,164
34
39
  bullish/exceptions.py,sha256=4z_i-dD-CDz1bkGmZH9DOf1L_awlCPCgdUDPF7dhWAI,106
35
40
  bullish/figures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- bullish/figures/figures.py,sha256=SWTTiEoVyWMZeIIxg0ERi23v7s4tySB5BLKyPu12jC4,4193
41
+ bullish/figures/figures.py,sha256=imrvIIcL9L-z-3vzWK5hDEsNttZs60QxlFI-PLw0hJQ,4829
37
42
  bullish/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- bullish/interface/interface.py,sha256=6HXSK-N-vOuOGVserizknP4CeUGbUhB8P642oZmgpk0,3252
43
+ bullish/interface/interface.py,sha256=UB2ATVtUsnXetnLCrSmNVrFpIvCw_0kuVxKHZC7sT7U,4233
39
44
  bullish/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
45
  bullish/jobs/app.py,sha256=5MJ5KXUo7JSNAvOPgkpIMasD11VTrjQvGzM7vmCY65E,77
41
46
  bullish/jobs/models.py,sha256=ndrGTMP08S57yGLGEG9TQt8Uw2slc4HvbG-TZtEEuN0,744
42
47
  bullish/jobs/tasks.py,sha256=V_b0c8_GQC0-KIxaHDlLFhtkclQJOsck0gXaW6OlC_w,3055
43
48
  bullish/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
49
  bullish/utils/checks.py,sha256=Va10_xDVVnxYkOD2hafvyQ-TFV8FQpOkr4huJ7XgpDM,2188
45
- bullishpy-0.13.0.dist-info/METADATA,sha256=5aWLV_c8a5ys2AjiyEGgx-CnRK1Qs3EBXdCbu77wSIw,784
46
- bullishpy-0.13.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
47
- bullishpy-0.13.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
48
- bullishpy-0.13.0.dist-info/RECORD,,
50
+ bullishpy-0.14.0.dist-info/METADATA,sha256=BH2BdzlEth8FoZFyxME0sbOlPnqqPdbHoxdHJ3X_GHg,784
51
+ bullishpy-0.14.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
52
+ bullishpy-0.14.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
53
+ bullishpy-0.14.0.dist-info/RECORD,,