bullishpy 0.4.0__py3-none-any.whl → 0.6.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.

@@ -4,33 +4,37 @@ import pandas as pd
4
4
  import plotly.graph_objects as go
5
5
  from plotly.subplots import make_subplots
6
6
 
7
+ from bullish.analysis.functions import add_indicators
8
+
7
9
 
8
10
  def plot(
9
11
  data: pd.DataFrame,
10
12
  symbol: str,
11
13
  name: Optional[str] = None,
12
- dates: Optional[pd.Series] = None, # type: ignore
14
+ dates: Optional[pd.Series] = None,
13
15
  ) -> go.Figure:
14
- data.ta.sma(50, append=True)
15
- data.ta.sma(200, append=True)
16
- data.ta.adx(append=True)
17
- data.ta.macd(append=True)
18
- data.ta.rsi(append=True)
16
+ data = add_indicators(data)
19
17
  fig = make_subplots(
20
- rows=4,
18
+ rows=7,
21
19
  cols=1,
22
20
  shared_xaxes=True,
23
- vertical_spacing=0.1,
21
+ vertical_spacing=0.05,
24
22
  specs=[
25
23
  [{"rowspan": 2}], # Row 1: main chart
26
24
  [None], # Row 2: skipped (part of row 1)
27
25
  [{}], # Row 3: RSI
28
26
  [{}], # Row 4: MACD
27
+ [{}], # Row 5: ADX
28
+ [{}], # Row 6: OBV
29
+ [{}], # Row 7: ATR
29
30
  ],
30
31
  subplot_titles=(
31
32
  f"Price + SMAs ({symbol} [{name}])",
32
33
  f"RSI ({symbol} [{name}])",
33
34
  f"MACD ({symbol} [{name}])",
35
+ f"ADX ({symbol} [{name}])",
36
+ f"OBV ({symbol} [{name}])",
37
+ f"ATR ({symbol} [{name}])",
34
38
  ),
35
39
  )
36
40
  # Row 1: Candlestick + SMAs
@@ -61,7 +65,7 @@ def plot(
61
65
 
62
66
  # Row 2: RSI
63
67
  fig.add_trace(
64
- go.Scatter(x=data.index, y=data.RSI_14, name="RSI 14", mode="lines"),
68
+ go.Scatter(x=data.index, y=data.RSI, name="RSI 14", mode="lines"),
65
69
  row=3,
66
70
  col=1,
67
71
  )
@@ -75,17 +79,52 @@ def plot(
75
79
 
76
80
  fig.add_trace(
77
81
  go.Scatter(
78
- x=data.index, y=data.MACDs_12_26_9, name="MACD Signal", mode="lines"
82
+ x=data.index, y=data.MACD_12_26_9_SIGNAL, name="MACD Signal", mode="lines"
79
83
  ),
80
84
  row=4,
81
85
  col=1,
82
86
  )
83
87
 
84
88
  fig.add_trace(
85
- go.Bar(x=data.index, y=data.MACDh_12_26_9, name="MACD Histogram", opacity=0.5),
89
+ go.Bar(
90
+ x=data.index, y=data.MACD_12_26_9_HIST, name="MACD Histogram", opacity=0.5
91
+ ),
86
92
  row=4,
87
93
  col=1,
88
94
  )
95
+
96
+ # Row 4: ADX
97
+ fig.add_trace(
98
+ go.Scatter(x=data.index, y=data.ADX_14, name="ADX_14", mode="lines"),
99
+ row=5,
100
+ col=1,
101
+ )
102
+
103
+ fig.add_trace(
104
+ go.Scatter(x=data.index, y=data.MINUS_DI, name="-DI", mode="lines"),
105
+ row=5,
106
+ col=1,
107
+ )
108
+ fig.add_trace(
109
+ go.Scatter(x=data.index, y=data.PLUS_DI, name="+DI", mode="lines"),
110
+ row=5,
111
+ col=1,
112
+ )
113
+ fig.add_trace(
114
+ go.Scatter(x=data.index, y=data.OBV, name="OBV", mode="lines"),
115
+ row=6,
116
+ col=1,
117
+ )
118
+ fig.add_trace(
119
+ go.Scatter(x=data.index, y=data.ADOSC, name="ADOSC", mode="lines"),
120
+ row=6,
121
+ col=1,
122
+ )
123
+ fig.add_trace(
124
+ go.Scatter(x=data.index, y=data.ATR, name="ATR", mode="lines"),
125
+ row=7,
126
+ col=1,
127
+ )
89
128
  if dates is not None and not dates.empty:
90
129
  for date in dates:
91
130
  fig.add_vline(
@@ -94,7 +133,7 @@ def plot(
94
133
 
95
134
  # Layout tweaks
96
135
  fig.update_layout(
97
- height=900,
136
+ height=1500,
98
137
  showlegend=True,
99
138
  title="Technical Indicator Dashboard",
100
139
  margin={"t": 60, "b": 40},
@@ -103,5 +142,6 @@ def plot(
103
142
  # Optional: Add horizontal lines for RSI (e.g., 70/30 levels)
104
143
  fig.add_hline(y=70, line_dash="dash", line_color="red", row=3, col=1)
105
144
  fig.add_hline(y=30, line_dash="dash", line_color="green", row=3, col=1)
145
+ fig.add_hline(y=25, line_dash="dash", line_color="red", row=5, col=1)
106
146
 
107
147
  return fig
@@ -23,11 +23,6 @@ class BullishDbBase(BearishDbBase): # type: ignore
23
23
 
24
24
  def read_filter_query(self, query: FilterQuery) -> pd.DataFrame:
25
25
 
26
- if not set(query.query_parameters).issubset(set(Analysis.model_fields)):
27
- raise ValueError(
28
- f"Query parameters {query.query_parameters} are not a "
29
- f"subset of Analysis model fields {Analysis.model_fields}"
30
- )
31
26
  query_ = query.to_query()
32
27
  fields = ",".join(list(AnalysisView.model_fields))
33
28
  query_str: str = f"""
@@ -50,47 +45,41 @@ class BullishDbBase(BearishDbBase): # type: ignore
50
45
  return add_icons(self._read_job_trackers())
51
46
 
52
47
  @abc.abstractmethod
53
- def _read_job_trackers(self) -> pd.DataFrame:
54
- ...
48
+ def _read_job_trackers(self) -> pd.DataFrame: ...
55
49
 
56
50
  @abc.abstractmethod
57
- def write_job_tracker(self, job_tracker: JobTracker) -> None:
58
- ...
51
+ def write_job_tracker(self, job_tracker: JobTracker) -> None: ...
59
52
 
60
53
  @abc.abstractmethod
61
- def delete_job_trackers(self, job_ids: List[str]) -> None:
62
- ...
54
+ def delete_job_trackers(self, job_ids: List[str]) -> None: ...
63
55
 
64
56
  @abc.abstractmethod
65
- def update_job_tracker_status(self, job_tracker_status: JobTrackerStatus) -> None:
66
- ...
57
+ def update_job_tracker_status(
58
+ self, job_tracker_status: JobTrackerStatus
59
+ ) -> None: ...
67
60
 
68
61
  @abc.abstractmethod
69
- def _write_analysis(self, analysis: "Analysis") -> None:
70
- ...
62
+ def _write_analysis(self, analysis: "Analysis") -> None: ...
71
63
 
72
64
  @abc.abstractmethod
73
- def _read_analysis(self, ticker: Ticker) -> Optional["Analysis"]:
74
- ...
65
+ def _read_analysis(self, ticker: Ticker) -> Optional["Analysis"]: ...
75
66
 
76
67
  @abc.abstractmethod
77
- def _read_filter_query(self, query: str) -> pd.DataFrame:
78
- ...
68
+ def _read_filter_query(self, query: str) -> pd.DataFrame: ...
79
69
 
80
70
  @abc.abstractmethod
81
71
  def _read_analysis_data(
82
72
  self, columns: List[str], symbols: Optional[List[str]] = None
83
- ) -> pd.DataFrame:
84
- ...
73
+ ) -> pd.DataFrame: ...
74
+
75
+ @abc.abstractmethod
76
+ def read_filtered_results(self, name: str) -> Optional[FilteredResults]: ...
85
77
 
86
78
  @abc.abstractmethod
87
- def read_filtered_results(self, name: str) -> Optional[FilteredResults]:
88
- ...
79
+ def read_list_filtered_results(self) -> List[str]: ...
89
80
 
90
81
  @abc.abstractmethod
91
- def read_list_filtered_results(self) -> List[str]:
92
- ...
82
+ def write_filtered_results(self, filtered_results: FilteredResults) -> None: ...
93
83
 
94
84
  @abc.abstractmethod
95
- def write_filtered_results(self, filtered_results: FilteredResults) -> None:
96
- ...
85
+ def read_symbols(self) -> List[str]: ...
bullish/jobs/tasks.py CHANGED
@@ -65,6 +65,16 @@ def update(
65
65
  run_analysis(bullish_db)
66
66
 
67
67
 
68
+ @huey.task(context=True) # type: ignore
69
+ @job_tracker
70
+ def analysis(
71
+ database_path: Path,
72
+ task: Optional[Task] = None,
73
+ ) -> None:
74
+ bullish_db = BullishDb(database_path=database_path)
75
+ run_analysis(bullish_db)
76
+
77
+
68
78
  @huey.task(context=True) # type: ignore
69
79
  @job_tracker
70
80
  def news(
File without changes
@@ -0,0 +1,64 @@
1
+ import sqlite3
2
+ from contextlib import contextmanager
3
+ from pathlib import Path
4
+ from sqlite3 import Connection
5
+ from typing import List, Generator
6
+
7
+ from bearish.database.schemas import * # type: ignore # noqa: F403
8
+ from bullish.database.schemas import * # noqa: F403
9
+
10
+
11
+ @contextmanager
12
+ def get_sqlite_connection(database_path: Path) -> Generator[Connection, None, None]:
13
+ conn = sqlite3.connect(database_path)
14
+ try:
15
+ yield conn
16
+ finally:
17
+ conn.close()
18
+
19
+
20
+ def get_table_names(module_name: str) -> List[str]:
21
+ return [
22
+ value.__tablename__
23
+ for _, value in locals().items()
24
+ if issubclass(value, SQLModel) # type: ignore # noqa: F405
25
+ and hasattr(value, "__tablename__")
26
+ and hasattr(value, "__table__")
27
+ and module_name in value.__module__
28
+ ]
29
+
30
+
31
+ def get_table_names_from_path(database_path: Path) -> List[str]:
32
+ with get_sqlite_connection(database_path) as conn:
33
+ cursor = conn.cursor()
34
+ cursor.execute(
35
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"
36
+ )
37
+ tables = [row[0] for row in cursor.fetchall()]
38
+ cursor.close()
39
+ return tables
40
+
41
+
42
+ def empty_analysis_table(database_path: Path) -> bool:
43
+ with get_sqlite_connection(database_path) as conn:
44
+ cursor = conn.cursor()
45
+
46
+ cursor.execute("SELECT COUNT(*) FROM analysis")
47
+ count = cursor.fetchone()[0]
48
+ conn.close()
49
+ return bool(count == 0)
50
+
51
+
52
+ def _compatible_table(database_path: Path, module_name: str) -> bool:
53
+ if not database_path.exists() and not database_path.is_file():
54
+ raise FileNotFoundError(f"Database file {database_path} does not exist.")
55
+ table_names = get_table_names(module_name)
56
+ return set(table_names).issubset(get_table_names_from_path(database_path))
57
+
58
+
59
+ def compatible_bearish_database(database_path: Path) -> bool:
60
+ return _compatible_table(database_path, "bearish.database.schemas")
61
+
62
+
63
+ def compatible_bullish_database(database_path: Path) -> bool:
64
+ return _compatible_table(database_path, "bullish.database.schemas")
@@ -1,21 +1,20 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bullishpy
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary:
5
5
  Author: aan
6
6
  Author-email: andoludovic.andriamamonjy@gmail.com
7
- Requires-Python: >=3.10,<3.13
7
+ Requires-Python: >=3.12,<3.13
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.10
10
- Classifier: Programming Language :: Python :: 3.11
11
9
  Classifier: Programming Language :: Python :: 3.12
12
- Requires-Dist: bearishpy (>=0.19.0,<0.20.0)
10
+ Requires-Dist: bearishpy (>=0.20.0,<0.21.0)
13
11
  Requires-Dist: huey (>=2.5.3,<3.0.0)
14
12
  Requires-Dist: pandas-ta (>=0.3.14b0,<0.4.0)
15
13
  Requires-Dist: plotly (>=6.1.2,<7.0.0)
16
14
  Requires-Dist: streamlit (>=1.45.1,<2.0.0)
17
15
  Requires-Dist: streamlit-file-browser (>=3.2.22,<4.0.0)
18
16
  Requires-Dist: streamlit-pydantic (>=v0.6.1-rc.3,<0.7.0)
17
+ Requires-Dist: ta-lib (>=0.6.4,<0.7.0)
19
18
  Requires-Dist: tickermood (>=0.4.0,<0.5.0)
20
19
  Description-Content-Type: text/markdown
21
20
 
@@ -0,0 +1,43 @@
1
+ bullish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ bullish/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ bullish/analysis/analysis.py,sha256=ZqIMdAq1NJYgoQZ52PsV724VsXK8Jtno4alFFd_7_XU,17842
4
+ bullish/analysis/filter.py,sha256=DzhA-cuKzZhIL1kwi61PTz77BBo8B6G_7EI4OVkPrww,17123
5
+ bullish/analysis/functions.py,sha256=7mT6P6seLlgezjQlOyJNNL1J2Nydo6WeMM3A62t82Zc,11691
6
+ bullish/analysis/indicators.py,sha256=LUNxhuimBdMbaIl5WpOu3Ofmw1Nv5ZSn7iVqdBlxoRY,16785
7
+ bullish/analysis/predefined_filters.py,sha256=Ln1Wjz2x9RqU0_-u9e3TUNT2UT2VHnuogET0Q4Z_RAQ,2708
8
+ bullish/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ bullish/app/app.py,sha256=Es244AnLce32d-MUYbKXZeEPE8GlfCUO4SQ7aiqooGc,12539
10
+ bullish/cli.py,sha256=C31Pj7XGzdLz2Y3nIPQ7CF1DvyGVU5EyLvzj423QbwQ,1915
11
+ bullish/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ bullish/database/alembic/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
13
+ bullish/database/alembic/alembic.ini,sha256=VuwqBJV5ObTyyRNrqv8Xr-TDIRfqPjP9R1mqewYM_xE,3695
14
+ bullish/database/alembic/env.py,sha256=TBsN4TyVppyc2QpWqViebd4-xxUT7Cs3GDYXQdKiAMs,2260
15
+ bullish/database/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
16
+ bullish/database/alembic/versions/037dbd721317_.py,sha256=U7EA4odH3t9w0-J4FmvBUt8HOuGDMn0rEAu_0vPUYaI,8595
17
+ bullish/database/alembic/versions/08ac1116e055_.py,sha256=zMEiCbraMEAZItT4ibc3evAH7-7mkXpdgnZy4tPVYeg,27263
18
+ bullish/database/alembic/versions/11d35a452b40_.py,sha256=j2PaU1RssLQ20OevGmBC7S9E9ocWiXpBue9SOS4AQoY,11521
19
+ bullish/database/alembic/versions/49c83f9eb5ac_.py,sha256=kCBItp7KmqpJ03roy5ikQjhefZia1oKgfZwournQDq8,3890
20
+ bullish/database/alembic/versions/4b0a2f40b7d3_.py,sha256=G0K7w7pOPYjPZkXTB8LWhxoxuWBPcPwOfnubTBtdeEY,1827
21
+ bullish/database/alembic/versions/73564b60fe24_.py,sha256=MTlDRDNHj3E9gK7IMeAzv2UxxxYtWiu3gI_9xTLE-wg,1008
22
+ bullish/database/alembic/versions/ee5baabb35f8_.py,sha256=nBMEY-_C8AsSXVPyaDdUkwrFFo2gxShzJhmrjejDwtc,1632
23
+ bullish/database/crud.py,sha256=2D0uDxJlDv1eJFRmgipiCQxCvlC5ILB2OR4OORlIJf4,5967
24
+ bullish/database/schemas.py,sha256=bU-DW49NqpBp--1VN486LUdDmLeScrI8TF69afzjoTc,1507
25
+ bullish/database/scripts/create_revision.py,sha256=rggIf-3koPqJNth8FIg89EOfnIM7a9QrvL8X7UJsP0g,628
26
+ bullish/database/scripts/stamp.py,sha256=PWgVUEBumjNUMjTnGw46qmU3p221LeN-KspnW_gFuu4,839
27
+ bullish/database/scripts/upgrade.py,sha256=-Gz7aFNPEt9y9e1kltqXE76-j_8QeNtet_VlwY5AWjo,806
28
+ bullish/database/settings.py,sha256=nMudufmF7iC_62_PHrGSMjlqDLN2I0qTbtz9JKZHSko,164
29
+ bullish/exceptions.py,sha256=4z_i-dD-CDz1bkGmZH9DOf1L_awlCPCgdUDPF7dhWAI,106
30
+ bullish/figures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ bullish/figures/figures.py,sha256=W4XJIs5wFtpX75OgoocVcuuA8Hdb_SNN58VW0LYI5oI,3808
32
+ bullish/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ bullish/interface/interface.py,sha256=T3MdJbX2ZF7hiMhnZ00ppXSXbDwyxaqD69a3M4bPswU,2806
34
+ bullish/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ bullish/jobs/app.py,sha256=5MJ5KXUo7JSNAvOPgkpIMasD11VTrjQvGzM7vmCY65E,77
36
+ bullish/jobs/models.py,sha256=ndrGTMP08S57yGLGEG9TQt8Uw2slc4HvbG-TZtEEuN0,744
37
+ bullish/jobs/tasks.py,sha256=gJEB342nCTw2KD3YgDXpQhGGITcXd14GAMiqRRVbZ-A,2757
38
+ bullish/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ bullish/utils/checks.py,sha256=rUyFNkx9F5DuOSxjldXymNHwRxIddN7PYbqPICnz1uM,2101
40
+ bullishpy-0.6.0.dist-info/METADATA,sha256=c6CwSmIdsRMmol4pyUig_AsSIJ3OfMO-lqJK-EYizT0,709
41
+ bullishpy-0.6.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
42
+ bullishpy-0.6.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
43
+ bullishpy-0.6.0.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- bullish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- bullish/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- bullish/analysis/analysis.py,sha256=JqaFzWfZ_AxF-7qa7BPmSWESnrcVdSEJKmUMRFGHzew,22168
4
- bullish/analysis/filter.py,sha256=rNqGGTIlaOq8Gw8mblX09bQOfR98by-NY8VY2TwP5oQ,3783
5
- bullish/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- bullish/app/app.py,sha256=Ef9IfrOJelV5_oymPFtEhyW438LDw0mlK6EhZR9Yqq8,7656
7
- bullish/cli.py,sha256=mxobC_49Zpn_qgXThVGhtpexjKLJS2tZZbOlo_wMLfg,1893
8
- bullish/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- bullish/database/alembic/README,sha256=heMzebYwlGhnE8_4CWJ4LS74WoEZjBy-S-mIJRxAEKI,39
10
- bullish/database/alembic/alembic.ini,sha256=VuwqBJV5ObTyyRNrqv8Xr-TDIRfqPjP9R1mqewYM_xE,3695
11
- bullish/database/alembic/env.py,sha256=TBsN4TyVppyc2QpWqViebd4-xxUT7Cs3GDYXQdKiAMs,2260
12
- bullish/database/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
13
- bullish/database/alembic/versions/037dbd721317_.py,sha256=pbmfCcJBFwy0SH42lfYVXawDlM72bR0oUUO-0RgFmUM,8594
14
- bullish/database/alembic/versions/4b0a2f40b7d3_.py,sha256=iyLvZY1Wiy7NucqxPi0TCAYD0Q8zmuFweMRZsAYx6o4,1826
15
- bullish/database/alembic/versions/73564b60fe24_.py,sha256=zp9Hvr8e3FWc9SLNqiQpbA8lsd0cU8DKDScKQdQwHYA,1007
16
- bullish/database/crud.py,sha256=xUSSzhHGp-KKBlG4iCNVtAEs9U5BNv4VhGSrLIR4fmM,5611
17
- bullish/database/schemas.py,sha256=FjFhCa_VijAu2EEWsQ6rShSRzdH6FS9IM66ibh2kx3g,1104
18
- bullish/database/scripts/create_revision.py,sha256=rggIf-3koPqJNth8FIg89EOfnIM7a9QrvL8X7UJsP0g,628
19
- bullish/database/scripts/stamp.py,sha256=PWgVUEBumjNUMjTnGw46qmU3p221LeN-KspnW_gFuu4,839
20
- bullish/database/scripts/upgrade.py,sha256=-Gz7aFNPEt9y9e1kltqXE76-j_8QeNtet_VlwY5AWjo,806
21
- bullish/database/settings.py,sha256=nMudufmF7iC_62_PHrGSMjlqDLN2I0qTbtz9JKZHSko,164
22
- bullish/exceptions.py,sha256=4z_i-dD-CDz1bkGmZH9DOf1L_awlCPCgdUDPF7dhWAI,106
23
- bullish/figures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- bullish/figures/figures.py,sha256=3Ifrnl4I7gq6DiMEWZs2P0589nEsaGKYNiq-Cxj35_g,2771
25
- bullish/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- bullish/interface/interface.py,sha256=1LiTFaMI1WXgUHLf73_KPiYKbv4RFcctyPxIcvzkkf0,3082
27
- bullish/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- bullish/jobs/app.py,sha256=5MJ5KXUo7JSNAvOPgkpIMasD11VTrjQvGzM7vmCY65E,77
29
- bullish/jobs/models.py,sha256=ndrGTMP08S57yGLGEG9TQt8Uw2slc4HvbG-TZtEEuN0,744
30
- bullish/jobs/tasks.py,sha256=vRjbCBcQciTC9283El_ji7BKxx40IbLcJkMbMVoE5wA,2533
31
- bullishpy-0.4.0.dist-info/METADATA,sha256=EVIlGsSkq8hAovop7OSQ_tNy2csZzF6QysWCrwXElNg,772
32
- bullishpy-0.4.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
33
- bullishpy-0.4.0.dist-info/entry_points.txt,sha256=eaPpmL6vmSBFo0FBtwibCXGqAW4LFJ83whJzT1VjD-0,43
34
- bullishpy-0.4.0.dist-info/RECORD,,