Smart-Trader-EA commited on
Commit
305d87a
ยท
1 Parent(s): 18fd386

Fix Gradio compatibility issue

Browse files
Files changed (1) hide show
  1. app.py +337 -91
app.py CHANGED
@@ -2,33 +2,30 @@ import gradio as gr
2
  import pandas as pd
3
  import numpy as np
4
  import plotly.graph_objects as go
5
- from prophet import Prophet
6
  import os
7
  import warnings
8
  import datetime
9
- import shutil
10
  import traceback
11
- import gc
12
  import tempfile
13
 
14
- # Suppress warnings
15
- warnings.filterwarnings('ignore')
16
 
17
- # Memory optimization
18
- def optimize_memory():
19
- gc.collect()
20
 
21
- # Environment setup
22
  os.environ["OMP_NUM_THREADS"] = "1"
23
  os.environ["OPENBLAS_NUM_THREADS"] = "1"
24
  os.environ["MKL_NUM_THREADS"] = "1"
25
 
26
- # Data directories
27
  RAW_DATA_DIR = "data/raw"
28
  PROCESSED_DATA_DIR = "data/processed"
29
  os.makedirs(PROCESSED_DATA_DIR, exist_ok=True)
30
 
31
- # Trading pairs config
32
  TRADING_PAIRS = {
33
  "EURUSD": {
34
  "description": "Euro to US Dollar Forex Pair",
@@ -39,19 +36,20 @@ TRADING_PAIRS = {
39
  }
40
  }
41
 
42
- # Data preprocessing (simplified)
43
  def preprocess_data_file(raw_file_path, pair_name):
 
44
  print(f"๐Ÿ”„ Preprocessing data for {pair_name}...")
 
45
  try:
46
- # Read CSV
47
  df = pd.read_csv(raw_file_path, encoding='utf-8')
48
- print(f"โœ… Successfully read {pair_name} data")
49
 
50
- # Standardize columns
51
  column_mapping = {}
52
  for col in df.columns:
53
  col_lower = col.lower().strip()
54
- if 'time' in col_lower or 'date' in col_lower:
55
  column_mapping[col] = 'datetime'
56
  elif 'open' in col_lower:
57
  column_mapping[col] = 'Open'
@@ -61,38 +59,92 @@ def preprocess_data_file(raw_file_path, pair_name):
61
  column_mapping[col] = 'Low'
62
  elif 'close' in col_lower:
63
  column_mapping[col] = 'Close'
 
 
64
 
65
  if column_mapping:
66
  df.rename(columns=column_mapping, inplace=True)
67
- print(f"๐Ÿท๏ธ Standardized columns: {list(column_mapping.keys())}")
68
-
69
- # Process datetime
70
- if 'datetime' in df.columns:
71
- df['datetime'] = pd.to_datetime(df['datetime'], errors='coerce', utc=True)
72
- df = df.dropna(subset=['datetime'])
73
- df.set_index('datetime', inplace=True)
74
- df.sort_index(inplace=True)
75
-
76
- # Save processed data
77
- processed_file = os.path.join(PROCESSED_DATA_DIR, f"{pair_name}_processed.csv")
78
- df.to_csv(processed_file)
79
- print(f"โœ… Saved preprocessed data to {processed_file}")
80
- return df
 
 
 
 
 
 
 
 
81
  else:
82
- print("โŒ No datetime column found")
83
- return None
84
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  except Exception as e:
86
- print(f"โŒ Preprocessing error: {str(e)}")
87
  traceback.print_exc()
88
  return None
89
 
90
- # Load available data
91
  def load_available_data():
 
 
92
  available_data = {}
93
 
 
94
  if not os.path.exists(RAW_DATA_DIR):
95
  print(f"โš ๏ธ Raw data directory not found: {RAW_DATA_DIR}")
 
 
 
 
 
 
 
 
 
 
96
  return available_data
97
 
98
  print(f"๐Ÿ” Scanning for data files in {RAW_DATA_DIR}...")
@@ -104,7 +156,7 @@ def load_available_data():
104
  if pair_name not in TRADING_PAIRS:
105
  TRADING_PAIRS[pair_name] = {
106
  "description": f"{pair_name} Trading Pair",
107
- "date_format": None,
108
  "has_timezone": False,
109
  "decimal_separator": ".",
110
  "required_columns": ["Open", "High", "Low", "Close"]
@@ -113,15 +165,17 @@ def load_available_data():
113
  raw_file_path = os.path.join(RAW_DATA_DIR, filename)
114
  processed_file_path = os.path.join(PROCESSED_DATA_DIR, f"{pair_name}_processed.csv")
115
 
 
116
  if os.path.exists(processed_file_path):
117
  try:
118
  df = pd.read_csv(processed_file_path, index_col=0, parse_dates=True)
119
  available_data[pair_name] = df
120
- print(f"โœ… Using existing preprocessed data for {pair_name}")
121
  continue
122
- except:
123
- pass
124
 
 
125
  print(f"๐Ÿ”„ Processing {pair_name} data...")
126
  df = preprocess_data_file(raw_file_path, pair_name)
127
  if df is not None:
@@ -130,45 +184,69 @@ def load_available_data():
130
 
131
  return available_data
132
 
133
- # Get available pairs - FIXED SYNTAX ERROR
134
  def get_available_pairs():
135
- """Get list of available trading pairs with status for UI"""
136
- if not available_data: # CORRECTED THIS LINE
137
- return "โš ๏ธ No data files found. Please upload CSV files to 'data/raw' directory."
138
 
139
  status = "โœ… Available trading pairs:\n"
140
  for pair in sorted(available_data.keys()):
141
  df = available_data[pair]
142
  records = len(df)
143
- date_range = f"{df.index.min().strftime('%Y-%m-%d')} to {df.index.max().strftime('%Y-%m-%d')}"
144
- status += f"โ€ข {pair}: {records} records ({date_range})\n"
 
 
 
145
  return status
146
 
147
- # Analysis function
148
- def analyze_trading_pair(pair_name):
149
  pair_name = pair_name.upper().strip()
150
  print(f"\n๐Ÿ” Starting analysis for {pair_name}")
151
 
152
  # Error fallbacks
153
- default_error_fig = go.Figure().update_layout(title="Analysis Failed", xaxis_title="Date", yaxis_title="Price")
154
- default_error_df = gr.DataFrame(headers=["Error"], value=[["Analysis failed"]])
 
 
 
 
 
 
 
 
 
 
155
 
156
- # Check if data available
157
  if pair_name not in available_data:
158
  available_pairs = ", ".join(available_data.keys()) or "None"
159
  return (
160
  f"โŒ Data not available for '{pair_name}'\nAvailable pairs: {available_pairs}",
161
- default_error_fig,
162
- default_error_fig,
163
  default_error_df
164
  )
165
 
166
  try:
167
- # Get data
168
  hist = available_data[pair_name].copy()
169
 
170
- # Create candlestick chart
 
 
 
 
 
 
 
 
 
 
 
171
  fig = go.Figure()
 
 
172
  fig.add_trace(go.Candlestick(
173
  x=hist.index,
174
  open=hist['Open'],
@@ -189,6 +267,16 @@ def analyze_trading_pair(pair_name):
189
  line=dict(color='blue', width=1.5)
190
  ))
191
 
 
 
 
 
 
 
 
 
 
 
192
  fig.update_layout(
193
  title=f"{pair_name} Price Analysis",
194
  xaxis_title="Date",
@@ -196,19 +284,127 @@ def analyze_trading_pair(pair_name):
196
  template="plotly_white",
197
  hovermode="x unified",
198
  height=500,
 
199
  )
200
 
201
- # Return results
202
- result_text = f"๐Ÿ“Š {pair_name} Analysis Complete\nCurrent Price: {hist['Close'].iloc[-1]:.5f}"
203
- return result_text, fig, default_error_fig, default_error_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  except Exception as e:
206
  error_msg = f"โŒ Analysis error: {str(e)}"
207
  print(error_msg)
208
  traceback.print_exc()
209
  return error_msg, default_error_fig, default_error_fig, default_error_df
210
 
211
- # Export function (simplified)
212
  def export_forecast(pair_name):
213
  """Export forecast data to CSV file"""
214
  try:
@@ -217,9 +413,15 @@ def export_forecast(pair_name):
217
  export_path = os.path.join(temp_dir, f"{pair_name}_forecast.csv")
218
 
219
  # Create dummy data for now
 
 
 
220
  pd.DataFrame({
221
- 'Date': pd.date_range(start=datetime.datetime.now(), periods=30),
222
- 'Predicted_Price': [1.0 + i*0.001 for i in range(30)]
 
 
 
223
  }).to_csv(export_path, index=False)
224
 
225
  return export_path
@@ -227,7 +429,14 @@ def export_forecast(pair_name):
227
  print(f"โŒ Export error: {str(e)}")
228
  return None
229
 
230
- # Initialize data
 
 
 
 
 
 
 
231
  print("๐Ÿš€ Initializing data processing system...")
232
  available_data = load_available_data()
233
  print(f"๐Ÿ“Š Available trading pairs: {list(available_data.keys())}")
@@ -235,48 +444,81 @@ print(f"๐Ÿ“Š Available trading pairs: {list(available_data.keys())}")
235
  # Create Gradio interface
236
  with gr.Blocks(title="Trading Pair AI Analyzer") as demo:
237
  gr.Markdown("# ๐Ÿ“ˆ Trading Pair AI Analysis System")
 
238
 
239
  with gr.Row():
240
- data_status = gr.Textbox(
241
- label="๐Ÿ“Š Available Data",
242
- value=get_available_pairs(),
243
- interactive=False,
244
- lines=5
245
- )
246
- system_info = gr.Textbox(
247
- value=f"๐Ÿ“ˆ Trading Analysis System v2.4\n๐Ÿ•’ Last updated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}\n๐Ÿงฎ Loaded pairs: {len(available_data)}",
248
- interactive=False,
249
- lines=3
250
- )
 
 
 
 
251
 
252
- refresh_btn = gr.Button("๐Ÿ”„ Refresh Data")
253
 
254
  with gr.Row():
255
- pair_input = gr.Textbox(
256
- label="๐Ÿ” Trading Pair to Analyze",
257
- value=list(available_data.keys())[0] if available_data else "EURUSD",
258
- placeholder="Enter pair name (e.g., EURUSD)"
259
- )
260
- analyze_btn = gr.Button("๐Ÿš€ Analyze Pair", variant="primary")
 
 
 
 
 
261
 
262
- result_output = gr.Textbox(label="๐Ÿ“ Analysis Results", lines=6)
263
 
264
  with gr.Tabs():
265
- with gr.TabItem("๐Ÿ“ˆ Price Chart"):
266
- price_chart = gr.Plot(label="Price Chart with Moving Averages")
267
- with gr.TabItem("๐Ÿ”ฎ Forecast Chart"):
268
- forecast_chart = gr.Plot(label="30-Day Forecast")
 
 
269
  with gr.TabItem("๐Ÿ“‹ Forecast Table"):
270
  forecast_table = gr.DataFrame(
271
  headers=["Date", "Predicted Price", "Lower Bound", "Upper Bound", "Trend"],
272
  value=[],
273
- label="30-Day Forecast Table"
 
 
274
  )
275
 
276
- export_btn = gr.Button("๐Ÿ“ฅ Export Forecast Data")
277
- export_output = gr.File(label="Download Forecast CSV", visible=False)
278
-
279
- # Event handlers - CORRECTED VERSION
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  analyze_btn.click(
281
  fn=analyze_trading_pair,
282
  inputs=pair_input,
@@ -284,7 +526,7 @@ with gr.Blocks(title="Trading Pair AI Analyzer") as demo:
284
  )
285
 
286
  refresh_btn.click(
287
- fn=lambda: (get_available_pairs(), f"๐Ÿ“ˆ Trading Analysis System v2.4\n๐Ÿ•’ Last updated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}\n๐Ÿงฎ Loaded pairs: {len(load_available_data())}"),
288
  inputs=[],
289
  outputs=[data_status, system_info]
290
  )
@@ -293,9 +535,13 @@ with gr.Blocks(title="Trading Pair AI Analyzer") as demo:
293
  fn=export_forecast,
294
  inputs=pair_input,
295
  outputs=export_output
 
 
 
 
296
  )
297
 
298
- # Launch app
299
  if __name__ == "__main__":
300
  demo.launch(
301
  server_name="0.0.0.0",
 
2
  import pandas as pd
3
  import numpy as np
4
  import plotly.graph_objects as go
 
5
  import os
6
  import warnings
7
  import datetime
 
8
  import traceback
9
+ import shutil
10
  import tempfile
11
 
12
+ # Disable Gradio queueing system (FIXES KeyError: 1 errors)
13
+ gr.queue = False
14
 
15
+ # Suppress warnings for cleaner output
16
+ warnings.filterwarnings('ignore')
 
17
 
18
+ # Performance optimization
19
  os.environ["OMP_NUM_THREADS"] = "1"
20
  os.environ["OPENBLAS_NUM_THREADS"] = "1"
21
  os.environ["MKL_NUM_THREADS"] = "1"
22
 
23
+ # Define data directories
24
  RAW_DATA_DIR = "data/raw"
25
  PROCESSED_DATA_DIR = "data/processed"
26
  os.makedirs(PROCESSED_DATA_DIR, exist_ok=True)
27
 
28
+ # Predefined trading pairs
29
  TRADING_PAIRS = {
30
  "EURUSD": {
31
  "description": "Euro to US Dollar Forex Pair",
 
36
  }
37
  }
38
 
 
39
  def preprocess_data_file(raw_file_path, pair_name):
40
+ """Preprocess raw data file to standardized format"""
41
  print(f"๐Ÿ”„ Preprocessing data for {pair_name}...")
42
+
43
  try:
44
+ # Read raw data
45
  df = pd.read_csv(raw_file_path, encoding='utf-8')
46
+ print(f"โœ… Successfully read {pair_name} data with utf-8 encoding")
47
 
48
+ # Standardize column names
49
  column_mapping = {}
50
  for col in df.columns:
51
  col_lower = col.lower().strip()
52
+ if any(keyword in col_lower for keyword in ['date', 'time', 'timestamp']):
53
  column_mapping[col] = 'datetime'
54
  elif 'open' in col_lower:
55
  column_mapping[col] = 'Open'
 
59
  column_mapping[col] = 'Low'
60
  elif 'close' in col_lower:
61
  column_mapping[col] = 'Close'
62
+ elif 'volume' in col_lower:
63
+ column_mapping[col] = 'Volume'
64
 
65
  if column_mapping:
66
  df.rename(columns=column_mapping, inplace=True)
67
+ print(f"๐Ÿท๏ธ Standardized columns: {list(column_mapping.keys())} โ†’ {list(column_mapping.values())}")
68
+
69
+ # Process datetime column
70
+ datetime_col = None
71
+ for col in ['datetime', 'date', 'time', 'timestamp']:
72
+ if col in df.columns:
73
+ datetime_col = col
74
+ break
75
+
76
+ if datetime_col is None:
77
+ raise Exception("โŒ No datetime column found in data")
78
+
79
+ # Handle EURUSD special format
80
+ if pair_name == "EURUSD" and df[datetime_col].astype(str).str.contains('GMT').any():
81
+ print("๐Ÿ•— Handling EURUSD special datetime format...")
82
+ df[datetime_col] = df[datetime_col].str.replace(' GMT', '', regex=False)
83
+ df[datetime_col] = pd.to_datetime(
84
+ df[datetime_col],
85
+ format="%d.%m.%Y %H:%M:%S.%f %z",
86
+ errors='coerce',
87
+ utc=True
88
+ )
89
  else:
90
+ df[datetime_col] = pd.to_datetime(
91
+ df[datetime_col],
92
+ errors='coerce',
93
+ utc=True
94
+ )
95
+
96
+ # Clean data
97
+ before_count = len(df)
98
+ df = df.dropna(subset=[datetime_col])
99
+ print(f"๐Ÿงน Removed {before_count - len(df)} rows with invalid dates")
100
+
101
+ # Set datetime as index
102
+ df.set_index(datetime_col, inplace=True)
103
+ df.sort_index(inplace=True)
104
+
105
+ # Fill missing values
106
+ for col in ['Open', 'High', 'Low', 'Close']:
107
+ if col in df.columns:
108
+ missing_before = df[col].isna().sum()
109
+ if missing_before > 0:
110
+ df[col] = df[col].fillna(method='ffill').fillna(method='bfill')
111
+ print(f" ๐Ÿ”„ Filled {missing_before} missing values in {col}")
112
+
113
+ # Remove duplicates
114
+ before_count = len(df)
115
+ df = df[~df.index.duplicated(keep='first')]
116
+ print(f"๐Ÿงน Removed {before_count - len(df)} duplicate entries")
117
+
118
+ # Save preprocessed data
119
+ processed_file = os.path.join(PROCESSED_DATA_DIR, f"{pair_name}_processed.csv")
120
+ df.to_csv(processed_file)
121
+ print(f"โœ… Saved preprocessed data to {processed_file}")
122
+
123
+ return df
124
+
125
  except Exception as e:
126
+ print(f"โŒ Preprocessing error for {pair_name}: {str(e)}")
127
  traceback.print_exc()
128
  return None
129
 
 
130
  def load_available_data():
131
+ """Load and preprocess all available data files"""
132
+ global available_data
133
  available_data = {}
134
 
135
+ # Check if raw data directory exists
136
  if not os.path.exists(RAW_DATA_DIR):
137
  print(f"โš ๏ธ Raw data directory not found: {RAW_DATA_DIR}")
138
+ # Check if data is in root directory instead
139
+ if os.path.exists("data") and os.path.isdir("data"):
140
+ for filename in os.listdir("data"):
141
+ if filename.endswith('.csv'):
142
+ os.makedirs(RAW_DATA_DIR, exist_ok=True)
143
+ shutil.move(os.path.join("data", filename), os.path.join(RAW_DATA_DIR, filename))
144
+ print(f"โœ… Moved {filename} to {RAW_DATA_DIR}")
145
+
146
+ if not os.path.exists(RAW_DATA_DIR):
147
+ print(f"โŒ Still cannot find raw data directory: {RAW_DATA_DIR}")
148
  return available_data
149
 
150
  print(f"๐Ÿ” Scanning for data files in {RAW_DATA_DIR}...")
 
156
  if pair_name not in TRADING_PAIRS:
157
  TRADING_PAIRS[pair_name] = {
158
  "description": f"{pair_name} Trading Pair",
159
+ "date_format": "%Y-%m-%d %H:%M:%S",
160
  "has_timezone": False,
161
  "decimal_separator": ".",
162
  "required_columns": ["Open", "High", "Low", "Close"]
 
165
  raw_file_path = os.path.join(RAW_DATA_DIR, filename)
166
  processed_file_path = os.path.join(PROCESSED_DATA_DIR, f"{pair_name}_processed.csv")
167
 
168
+ # Check for existing preprocessed file
169
  if os.path.exists(processed_file_path):
170
  try:
171
  df = pd.read_csv(processed_file_path, index_col=0, parse_dates=True)
172
  available_data[pair_name] = df
173
+ print(f"โœ… Using existing preprocessed data for {pair_name} with {len(df)} records")
174
  continue
175
+ except Exception as e:
176
+ print(f"โš ๏ธ Error loading preprocessed file: {str(e)}. Reprocessing.")
177
 
178
+ # Preprocess the file
179
  print(f"๐Ÿ”„ Processing {pair_name} data...")
180
  df = preprocess_data_file(raw_file_path, pair_name)
181
  if df is not None:
 
184
 
185
  return available_data
186
 
 
187
  def get_available_pairs():
188
+ """Get list of available trading pairs with status"""
189
+ if not available_data:
190
+ return "โš ๏ธ No data files found. Please upload CSV files to the 'data/raw' directory."
191
 
192
  status = "โœ… Available trading pairs:\n"
193
  for pair in sorted(available_data.keys()):
194
  df = available_data[pair]
195
  records = len(df)
196
+ if records > 0:
197
+ date_range = f"{df.index.min().strftime('%Y-%m-%d')} to {df.index.max().strftime('%Y-%m-%d')}"
198
+ status += f"โ€ข {pair}: {records} records ({date_range})\n"
199
+ else:
200
+ status += f"โ€ข {pair}: 0 records (Data Error)\n"
201
  return status
202
 
203
+ def analyze_trading_pair(pair_name: str):
204
+ """Analyze a specific trading pair"""
205
  pair_name = pair_name.upper().strip()
206
  print(f"\n๐Ÿ” Starting analysis for {pair_name}")
207
 
208
  # Error fallbacks
209
+ default_error_fig = go.Figure().update_layout(
210
+ title="Analysis Failed",
211
+ xaxis_title="Date",
212
+ yaxis_title="Price",
213
+ template="plotly_white",
214
+ height=500
215
+ )
216
+ default_error_df = gr.DataFrame(
217
+ headers=["Error"],
218
+ value=[["Analysis failed - check logs for details"]],
219
+ interactive=False
220
+ )
221
 
222
+ # Check if data is available
223
  if pair_name not in available_data:
224
  available_pairs = ", ".join(available_data.keys()) or "None"
225
  return (
226
  f"โŒ Data not available for '{pair_name}'\nAvailable pairs: {available_pairs}",
227
+ default_error_fig,
228
+ default_error_fig,
229
  default_error_df
230
  )
231
 
232
  try:
 
233
  hist = available_data[pair_name].copy()
234
 
235
+ # Basic data validation
236
+ required_cols = ['Open', 'High', 'Low', 'Close']
237
+ if not all(col in hist.columns for col in required_cols):
238
+ missing_cols = [col for col in required_cols if col not in hist.columns]
239
+ return (
240
+ f"โŒ Missing required columns: {', '.join(missing_cols)}\nAvailable columns: {', '.join(hist.columns)}",
241
+ default_error_fig,
242
+ default_error_fig,
243
+ default_error_df
244
+ )
245
+
246
+ # --- 1. Candlestick Chart with Technical Indicators (MAs) ---
247
  fig = go.Figure()
248
+
249
+ # Add candlestick
250
  fig.add_trace(go.Candlestick(
251
  x=hist.index,
252
  open=hist['Open'],
 
267
  line=dict(color='blue', width=1.5)
268
  ))
269
 
270
+ if len(hist) >= 50:
271
+ hist['MA50'] = hist['Close'].rolling(window=50, min_periods=1).mean()
272
+ fig.add_trace(go.Scatter(
273
+ x=hist.index,
274
+ y=hist['MA50'],
275
+ mode='lines',
276
+ name='50-period MA',
277
+ line=dict(color='orange', width=1.5)
278
+ ))
279
+
280
  fig.update_layout(
281
  title=f"{pair_name} Price Analysis",
282
  xaxis_title="Date",
 
284
  template="plotly_white",
285
  hovermode="x unified",
286
  height=500,
287
+ margin=dict(l=50, r=50, t=50, b=50)
288
  )
289
 
290
+ # --- 2. Simple Forecast (without Prophet to avoid import issues) ---
291
+ forecast_fig = default_error_fig
292
+ forecast_table = default_error_df
293
+ forecast_result = "Forecast functionality will be available soon."
294
+
295
+ try:
296
+ # Simple linear forecast as fallback
297
+ if len(hist) >= 30:
298
+ # Take last 30 days
299
+ recent_data = hist['Close'].tail(30)
300
+ dates = recent_data.index
301
+
302
+ # Create simple trend line
303
+ x = np.arange(len(recent_data))
304
+ y = recent_data.values
305
+ slope, intercept = np.polyfit(x, y, 1)
306
+
307
+ # Create forecast data
308
+ future_dates = [dates[-1] + datetime.timedelta(days=i) for i in range(1, 31)]
309
+ future_values = [slope * (len(x) + i) + intercept for i in range(30)]
310
+
311
+ # Create forecast chart
312
+ forecast_fig = go.Figure()
313
+ forecast_fig.add_trace(go.Scatter(
314
+ x=dates,
315
+ y=recent_data.values,
316
+ mode='lines',
317
+ name='Historical',
318
+ line=dict(color='blue', width=2)
319
+ ))
320
+ forecast_fig.add_trace(go.Scatter(
321
+ x=future_dates,
322
+ y=future_values,
323
+ mode='lines',
324
+ name='Forecast',
325
+ line=dict(color='red', width=2, dash='dash')
326
+ ))
327
+ forecast_fig.update_layout(
328
+ title=f"{pair_name} 30-Day Price Forecast (Simple Trend)",
329
+ xaxis_title="Date",
330
+ yaxis_title="Price",
331
+ template="plotly_white",
332
+ height=500,
333
+ hovermode="x unified"
334
+ )
335
+
336
+ # Create forecast table
337
+ table_data = []
338
+ for i, (date, value) in enumerate(zip(future_dates, future_values)):
339
+ trend = "๐Ÿ“ˆ Rising" if slope > 0 else "๐Ÿ“‰ Falling"
340
+ table_data.append([
341
+ date.strftime('%Y-%m-%d'),
342
+ f"{value:.5f}",
343
+ f"{value * 0.98:.5f}",
344
+ f"{value * 1.02:.5f}",
345
+ trend
346
+ ])
347
+
348
+ forecast_table = gr.DataFrame(
349
+ headers=["Date", "Predicted Price", "Lower Bound", "Upper Bound", "Trend"],
350
+ value=table_data,
351
+ datatype=["str", "str", "str", "str", "str"],
352
+ label=f"{pair_name} 30-Day Price Forecast Table",
353
+ interactive=False
354
+ )
355
+
356
+ forecast_result = (
357
+ f"๐Ÿ”ฎ 30-Day Forecast (Simple Trend):\n"
358
+ f"Projected price range based on recent trend"
359
+ )
360
+
361
+ except Exception as e:
362
+ print(f"โš ๏ธ Forecasting error: {str(e)}")
363
+ forecast_result = f"โš ๏ธ Forecasting error: {str(e)}"
364
+
365
+ # Technical analysis
366
+ current_price = hist['Close'].iloc[-1]
367
+ signal = "๐Ÿ“Š Analyzing market conditions..."
368
+
369
+ if 'MA20' in hist.columns and 'MA50' in hist.columns:
370
+ ma20 = hist['MA20'].iloc[-1]
371
+ ma50 = hist['MA50'].iloc[-1]
372
+
373
+ if current_price > ma20 > ma50:
374
+ signal = "๐Ÿš€ STRONG BULLISH: Golden Cross pattern"
375
+ elif current_price < ma20 < ma50:
376
+ signal = "๐Ÿ’ฃ STRONG BEARISH: Death Cross pattern"
377
+ elif current_price > ma20:
378
+ signal = "๐Ÿ“ˆ BULLISH: Price above 20-period MA"
379
+ else:
380
+ signal = "๐Ÿ“‰ BEARISH: Price below 20-period MA"
381
+
382
+ # Calculate performance metrics
383
+ start_price = hist['Close'].iloc[0]
384
+ total_return = (current_price / start_price - 1) * 100
385
+ volatility = hist['Close'].pct_change().std() * np.sqrt(252) * 100
386
 
387
+ # Create result text
388
+ result_text = (
389
+ f"๐Ÿ“Š {pair_name} Analysis Report\n"
390
+ f"{'=' * 40}\n"
391
+ f"๐Ÿ’ฐ Current Price: {current_price:.5f}\n"
392
+ f"๐Ÿ“ˆ Total Return: {total_return:.2f}%\n"
393
+ f"โšก Volatility: {volatility:.2f}%\n"
394
+ f"๐ŸŽฏ Signal: {signal}\n"
395
+ f"{'=' * 40}\n"
396
+ f"{forecast_result}"
397
+ )
398
+
399
+ print(f"โœ… Analysis completed for {pair_name}")
400
+ return result_text, fig, forecast_fig, forecast_table
401
+
402
  except Exception as e:
403
  error_msg = f"โŒ Analysis error: {str(e)}"
404
  print(error_msg)
405
  traceback.print_exc()
406
  return error_msg, default_error_fig, default_error_fig, default_error_df
407
 
 
408
  def export_forecast(pair_name):
409
  """Export forecast data to CSV file"""
410
  try:
 
413
  export_path = os.path.join(temp_dir, f"{pair_name}_forecast.csv")
414
 
415
  # Create dummy data for now
416
+ dates = [datetime.datetime.now() + datetime.timedelta(days=i) for i in range(30)]
417
+ prices = [1.0800 + i*0.0005 for i in range(30)]
418
+
419
  pd.DataFrame({
420
+ 'Date': [d.strftime('%Y-%m-%d') for d in dates],
421
+ 'Predicted_Price': prices,
422
+ 'Lower_Bound': [p * 0.998 for p in prices],
423
+ 'Upper_Bound': [p * 1.002 for p in prices],
424
+ 'Trend': ['Rising' if prices[i] > prices[i-1] else 'Falling' for i in range(30)]
425
  }).to_csv(export_path, index=False)
426
 
427
  return export_path
 
429
  print(f"โŒ Export error: {str(e)}")
430
  return None
431
 
432
+ def refresh_data():
433
+ """Refresh available data"""
434
+ global available_data
435
+ print("๐Ÿ”„ Refreshing data...")
436
+ available_data = load_available_data()
437
+ return get_available_pairs(), f"๐Ÿ“ˆ Trading Analysis System v2.4\n๐Ÿ•’ Last updated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}\n๐Ÿงฎ Loaded pairs: {len(available_data)}"
438
+
439
+ # Load available data at startup
440
  print("๐Ÿš€ Initializing data processing system...")
441
  available_data = load_available_data()
442
  print(f"๐Ÿ“Š Available trading pairs: {list(available_data.keys())}")
 
444
  # Create Gradio interface
445
  with gr.Blocks(title="Trading Pair AI Analyzer") as demo:
446
  gr.Markdown("# ๐Ÿ“ˆ Trading Pair AI Analysis System")
447
+ gr.Markdown("### Analyze forex data with interactive charts and forecasts")
448
 
449
  with gr.Row():
450
+ with gr.Column(scale=2):
451
+ data_status = gr.Textbox(
452
+ label="๐Ÿ“Š Available Data",
453
+ value=get_available_pairs(),
454
+ interactive=False,
455
+ lines=5
456
+ )
457
+
458
+ with gr.Column(scale=1):
459
+ gr.Markdown("### โ„น๏ธ System Information")
460
+ system_info = gr.Textbox(
461
+ value=f"๐Ÿ“ˆ Trading Analysis System v2.4\n๐Ÿ•’ Last updated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}\n๐Ÿงฎ Loaded pairs: {len(available_data)}",
462
+ interactive=False,
463
+ lines=3
464
+ )
465
 
466
+ refresh_btn = gr.Button("๐Ÿ”„ Refresh Data", variant="secondary")
467
 
468
  with gr.Row():
469
+ with gr.Column(scale=2):
470
+ pair_input = gr.Textbox(
471
+ label="๐Ÿ” Trading Pair to Analyze",
472
+ value=list(available_data.keys())[0] if available_data else "EURUSD",
473
+ placeholder="Enter pair name (e.g., EURUSD)"
474
+ )
475
+ analyze_btn = gr.Button("๐Ÿš€ Analyze Pair", variant="primary")
476
+
477
+ with gr.Column(scale=1):
478
+ export_btn = gr.Button("๐Ÿ“ฅ Export Forecast Data", variant="secondary")
479
+ export_output = gr.File(label="Download Forecast CSV", visible=False)
480
 
481
+ result_output = gr.Textbox(label="๐Ÿ“ Analysis Results", lines=8)
482
 
483
  with gr.Tabs():
484
+ with gr.TabItem("๐Ÿ“ˆ Price Chart & Indicators"):
485
+ price_chart = gr.Plot(label="Candlestick Chart with Moving Averages")
486
+
487
+ with gr.TabItem("๐Ÿ”ฎ Price Forecast Chart"):
488
+ forecast_chart = gr.Plot(label="30-Day Price Forecast")
489
+
490
  with gr.TabItem("๐Ÿ“‹ Forecast Table"):
491
  forecast_table = gr.DataFrame(
492
  headers=["Date", "Predicted Price", "Lower Bound", "Upper Bound", "Trend"],
493
  value=[],
494
+ datatype=["str", "str", "str", "str", "str"],
495
+ label="30-Day Price Forecast Table",
496
+ interactive=False
497
  )
498
 
499
+ with gr.Accordion("๐Ÿ“ Data Upload Instructions", open=False):
500
+ gr.Markdown("""
501
+ ### How to Add Your Own Data
502
+
503
+ 1. **Prepare your CSV file** with these columns:
504
+ - Date/Time column (any format)
505
+ - Open, High, Low, Close prices
506
+ - Volume (optional)
507
+
508
+ 2. **Upload to Hugging Face Space**:
509
+ - Go to your Space Files tab
510
+ - Create directories: `data/raw/`
511
+ - Upload your CSV files to `data/raw/`
512
+ - Example filenames: `EURUSD.csv`
513
+
514
+ 3. **Refresh the application**:
515
+ - Click the "๐Ÿ”„ Refresh Data" button
516
+ - Wait for data to load
517
+
518
+ 4. **Your data will be automatically preprocessed** and ready for analysis!
519
+ """)
520
+
521
+ # Event handlers
522
  analyze_btn.click(
523
  fn=analyze_trading_pair,
524
  inputs=pair_input,
 
526
  )
527
 
528
  refresh_btn.click(
529
+ fn=refresh_data,
530
  inputs=[],
531
  outputs=[data_status, system_info]
532
  )
 
535
  fn=export_forecast,
536
  inputs=pair_input,
537
  outputs=export_output
538
+ ).then(
539
+ fn=lambda: gr.update(visible=True),
540
+ inputs=None,
541
+ outputs=export_output
542
  )
543
 
544
+ # Launch the app
545
  if __name__ == "__main__":
546
  demo.launch(
547
  server_name="0.0.0.0",