eshan6704 commited on
Commit
08519ee
·
verified ·
1 Parent(s): c1fcb74

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -127
app.py CHANGED
@@ -1,10 +1,3 @@
1
- # =========================================================
2
- # TALib + mplfinance + Gradio
3
- # 1️⃣ Load Data (Internet only)
4
- # 2️⃣ Pattern Selection
5
- # 3️⃣ Build Candlestick Chart + Pattern Marking
6
- # =========================================================
7
-
8
  import yfinance as yf
9
  import pandas as pd
10
  import numpy as np
@@ -14,192 +7,125 @@ import gradio as gr
14
  import os
15
  from datetime import date
16
 
17
- # ---------------------------------------------------------
18
- # TALib Pattern Map (UI name TALib name)
19
- # ---------------------------------------------------------
20
- TALIB_PATTERNS = sorted([p for p in dir(talib) if p.startswith("CDL")])
21
  PATTERN_MAP = {p.replace("CDL", ""): p for p in TALIB_PATTERNS}
22
- PATTERN_CHOICES = ["None"] + list(PATTERN_MAP.keys())
23
 
24
- # ---------------------------------------------------------
25
- # DATA CLEANING (MultiIndex SAFE)
26
- # ---------------------------------------------------------
27
  def clean_ohlc(df):
28
- if df is None or df.empty:
29
- raise ValueError("Empty dataframe")
30
-
31
  df = df.copy()
32
 
33
- # ---- MultiIndex handling ----
34
  if isinstance(df.columns, pd.MultiIndex):
35
  df.columns = df.columns.get_level_values(0)
36
 
37
- df.columns = list(df.columns)
38
  df.index.name = None
39
 
40
- # normalize column names
41
- df.columns = [str(c).lower().strip() for c in df.columns]
42
-
43
- # rename to mplfinance standard
44
- rename_map = {
45
  "open": "Open",
46
  "high": "High",
47
  "low": "Low",
48
  "close": "Close",
49
  "volume": "Volume"
50
- }
51
- df = df.rename(columns=rename_map)
52
 
53
- # ensure datetime index
54
- if not isinstance(df.index, pd.DatetimeIndex):
55
- df.index = pd.to_datetime(df.index, errors="coerce")
56
 
57
- # numeric conversion
58
- for col in ["Open", "High", "Low", "Close", "Volume"]:
59
- if col in df.columns:
60
- df[col] = pd.to_numeric(df[col], errors="coerce")
61
 
62
- # drop invalid rows
63
  df = df.dropna(subset=["Open", "High", "Low", "Close"])
64
  df = df.sort_index()
65
 
66
- if df.empty:
67
- raise ValueError("No valid OHLC data after cleaning")
68
-
69
  return df
70
 
71
- # ---------------------------------------------------------
72
- # 1️⃣ LOAD DATA (Internet only)
73
- # ---------------------------------------------------------
74
- def load_data(symbol, start_date, end_date):
75
  if not symbol:
76
  return None, "❌ Symbol required"
77
 
78
- try:
79
- df = yf.download(symbol, start=start_date, end=end_date, progress=False)
80
- if df.empty:
81
- return None, "❌ No data found"
82
-
83
- df = clean_ohlc(df)
84
- return df, f"✅ Data loaded ({len(df)} rows)"
85
 
86
- except Exception as e:
87
- return None, f" Load error: {e}"
88
 
89
- # ---------------------------------------------------------
90
- # 2️⃣ PATTERN MARKER BUILDER
91
- # ---------------------------------------------------------
92
- def build_pattern_addplots(df, pattern):
93
  if pattern == "None":
94
  return []
95
 
96
- talib_name = PATTERN_MAP.get(pattern)
97
- func = getattr(talib, talib_name)
 
98
 
99
- result = func(
100
- df["Open"].values,
101
- df["High"].values,
102
- df["Low"].values,
103
- df["Close"].values
104
- )
105
 
106
- s = pd.Series(result, index=df.index)
107
- addplots = []
108
-
109
- # bullish
110
  if (s > 0).any():
111
  bull = pd.Series(np.nan, index=df.index)
112
  bull[s > 0] = df["Low"][s > 0] * 0.98
113
- addplots.append(
114
- mpf.make_addplot(
115
- bull,
116
- type="scatter",
117
- marker="^",
118
- color="green",
119
- markersize=90
120
- )
121
- )
122
-
123
- # bearish
124
  if (s < 0).any():
125
  bear = pd.Series(np.nan, index=df.index)
126
  bear[s < 0] = df["High"][s < 0] * 1.02
127
- addplots.append(
128
- mpf.make_addplot(
129
- bear,
130
- type="scatter",
131
- marker="v",
132
- color="red",
133
- markersize=90
134
- )
135
- )
136
-
137
- return addplots
138
-
139
- # ---------------------------------------------------------
140
- # 3️⃣ BUILD CANDLESTICK CHART (NO INTERNET)
141
- # ---------------------------------------------------------
142
  def build_chart(df, symbol, pattern):
143
  if df is None:
144
  return None, "❌ Load data first"
145
 
146
- addplots = build_pattern_addplots(df, pattern)
147
- has_volume = "Volume" in df.columns
148
-
149
  os.makedirs("/tmp", exist_ok=True)
150
- path = f"/tmp/{symbol}_candlestick_{pattern}.png"
151
 
152
  fig, _ = mpf.plot(
153
  df,
154
  type="candle",
155
- volume=has_volume,
156
  addplot=addplots if addplots else None,
157
  style="yahoo",
158
- title=f"{symbol} | Candlestick | {pattern}",
159
  figscale=1.8,
160
  returnfig=True
161
  )
162
 
163
  fig.savefig(path, dpi=150, bbox_inches="tight")
164
- return path, "✅ Candlestick chart built successfully"
165
 
166
- # ---------------------------------------------------------
167
- # =================== GRADIO UI ===========================
168
- # ---------------------------------------------------------
169
  with gr.Blocks(fill_height=True) as app:
170
- gr.Markdown("## 📊 Candlestick Pattern Analyzer (Clean 3-Step App)")
171
 
172
  state_df = gr.State(None)
173
 
174
- # ---------------- LOAD DATA ----------------
175
  with gr.Row():
176
- with gr.Column():
177
- gr.Markdown("### 1️⃣ Load Data")
178
- symbol = gr.Textbox(label="Symbol", value="MSFT")
179
- start = gr.Textbox(label="Start Date", value="2024-01-01")
180
- end = gr.Textbox(
181
- label="End Date",
182
- value=date.today().strftime("%Y-%m-%d")
183
- )
184
- load_btn = gr.Button("Load Data", variant="primary")
185
- load_status = gr.Textbox(label="Load Status")
186
-
187
- # ---------------- BUILD SECTION ----------------
188
  with gr.Row():
189
  with gr.Column(scale=1):
190
- gr.Markdown("### 2️⃣ Pattern")
191
- pattern = gr.Dropdown(
192
- PATTERN_CHOICES,
193
- value="None"
194
- )
195
-
196
- build_btn = gr.Button("Build Chart", variant="primary")
197
 
198
  with gr.Column(scale=3):
199
- chart = gr.Image(label="Candlestick Chart", height=600)
200
- build_status = gr.Textbox(label="Build Status")
201
 
202
- # ---------------- EVENTS ----------------
203
  load_btn.click(
204
  load_data,
205
  inputs=[symbol, start, end],
@@ -212,5 +138,12 @@ with gr.Blocks(fill_height=True) as app:
212
  outputs=[chart, build_status]
213
  )
214
 
 
 
 
 
 
 
 
215
  if __name__ == "__main__":
216
  app.launch()
 
 
 
 
 
 
 
 
1
  import yfinance as yf
2
  import pandas as pd
3
  import numpy as np
 
7
  import os
8
  from datetime import date
9
 
10
+ # ---------------- TALib Patterns ----------------
11
+ TALIB_PATTERNS = sorted(p for p in dir(talib) if p.startswith("CDL"))
 
 
12
  PATTERN_MAP = {p.replace("CDL", ""): p for p in TALIB_PATTERNS}
13
+ PATTERNS = ["None"] + list(PATTERN_MAP.keys())
14
 
15
+ # ---------------- Data Cleaning ----------------
 
 
16
  def clean_ohlc(df):
 
 
 
17
  df = df.copy()
18
 
 
19
  if isinstance(df.columns, pd.MultiIndex):
20
  df.columns = df.columns.get_level_values(0)
21
 
22
+ df.columns = [c.lower() for c in df.columns]
23
  df.index.name = None
24
 
25
+ df = df.rename(columns={
 
 
 
 
26
  "open": "Open",
27
  "high": "High",
28
  "low": "Low",
29
  "close": "Close",
30
  "volume": "Volume"
31
+ })
 
32
 
33
+ df.index = pd.to_datetime(df.index, errors="coerce")
 
 
34
 
35
+ for c in ["Open", "High", "Low", "Close", "Volume"]:
36
+ if c in df.columns:
37
+ df[c] = pd.to_numeric(df[c], errors="coerce")
 
38
 
 
39
  df = df.dropna(subset=["Open", "High", "Low", "Close"])
40
  df = df.sort_index()
41
 
 
 
 
42
  return df
43
 
44
+ # ---------------- Load Data ----------------
45
+ def load_data(symbol, start, end):
 
 
46
  if not symbol:
47
  return None, "❌ Symbol required"
48
 
49
+ df = yf.download(symbol, start=start, end=end, progress=False)
50
+ if df.empty:
51
+ return None, "❌ No data found"
 
 
 
 
52
 
53
+ df = clean_ohlc(df)
54
+ return df, f" Loaded {len(df)} rows"
55
 
56
+ # ---------------- Pattern Builder ----------------
57
+ def build_pattern(df, pattern):
 
 
58
  if pattern == "None":
59
  return []
60
 
61
+ func = getattr(talib, PATTERN_MAP[pattern])
62
+ res = func(df["Open"], df["High"], df["Low"], df["Close"])
63
+ s = pd.Series(res, index=df.index)
64
 
65
+ aps = []
 
 
 
 
 
66
 
 
 
 
 
67
  if (s > 0).any():
68
  bull = pd.Series(np.nan, index=df.index)
69
  bull[s > 0] = df["Low"][s > 0] * 0.98
70
+ aps.append(mpf.make_addplot(bull, type="scatter",
71
+ marker="^", color="green", markersize=90))
72
+
 
 
 
 
 
 
 
 
73
  if (s < 0).any():
74
  bear = pd.Series(np.nan, index=df.index)
75
  bear[s < 0] = df["High"][s < 0] * 1.02
76
+ aps.append(mpf.make_addplot(bear, type="scatter",
77
+ marker="v", color="red", markersize=90))
78
+
79
+ return aps
80
+
81
+ # ---------------- Build Chart ----------------
 
 
 
 
 
 
 
 
 
82
  def build_chart(df, symbol, pattern):
83
  if df is None:
84
  return None, "❌ Load data first"
85
 
86
+ addplots = build_pattern(df, pattern)
 
 
87
  os.makedirs("/tmp", exist_ok=True)
88
+ path = f"/tmp/{symbol}_{pattern}.png"
89
 
90
  fig, _ = mpf.plot(
91
  df,
92
  type="candle",
93
+ volume="Volume" in df.columns,
94
  addplot=addplots if addplots else None,
95
  style="yahoo",
96
+ title=f"{symbol} | {pattern}",
97
  figscale=1.8,
98
  returnfig=True
99
  )
100
 
101
  fig.savefig(path, dpi=150, bbox_inches="tight")
102
+ return path, "✅ Chart rebuilt"
103
 
104
+ # ================= GRADIO APP =================
 
 
105
  with gr.Blocks(fill_height=True) as app:
106
+ gr.Markdown("## 📊 Candlestick Pattern Analyzer")
107
 
108
  state_df = gr.State(None)
109
 
110
+ # -------- Load Section --------
111
  with gr.Row():
112
+ symbol = gr.Textbox(label="Symbol", value="MSFT")
113
+ start = gr.Textbox(label="Start Date", value="2024-01-01")
114
+ end = gr.Textbox(label="End Date", value=date.today().strftime("%Y-%m-%d"))
115
+ load_btn = gr.Button("Load Data", variant="primary")
116
+ load_status = gr.Textbox(label="Load Status")
117
+
118
+ # -------- Pattern + Chart --------
 
 
 
 
 
119
  with gr.Row():
120
  with gr.Column(scale=1):
121
+ pattern = gr.Dropdown(PATTERNS, value="None", label="Pattern")
122
+ build_btn = gr.Button("Build Chart")
 
 
 
 
 
123
 
124
  with gr.Column(scale=3):
125
+ chart = gr.Image(height=600)
126
+ build_status = gr.Textbox(label="Status")
127
 
128
+ # -------- Events --------
129
  load_btn.click(
130
  load_data,
131
  inputs=[symbol, start, end],
 
138
  outputs=[chart, build_status]
139
  )
140
 
141
+ # 🔥 AUTO REBUILD WHEN PATTERN CHANGES
142
+ pattern.change(
143
+ build_chart,
144
+ inputs=[state_df, symbol, pattern],
145
+ outputs=[chart, build_status]
146
+ )
147
+
148
  if __name__ == "__main__":
149
  app.launch()