Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
from bs4 import BeautifulSoup
|
| 3 |
+
import pandas as pd
|
| 4 |
+
from io import StringIO
|
| 5 |
+
from datetime import datetime, timedelta
|
| 6 |
+
from openai import OpenAI
|
| 7 |
+
import gradio as gr
|
| 8 |
+
|
| 9 |
+
OPENROUTER_API_KEY = "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"
|
| 10 |
+
|
| 11 |
+
HEADERS = {
|
| 12 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
| 13 |
+
'Accept-Language': 'en-US,en;q=0.9',
|
| 14 |
+
'Referer': 'https://www.google.com/'
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
def get_current_price(symbol: str):
|
| 18 |
+
url = f'https://www.marketwatch.com/investing/stock/{symbol}'
|
| 19 |
+
response = requests.get(url, headers=HEADERS)
|
| 20 |
+
if response.status_code == 200:
|
| 21 |
+
soup = BeautifulSoup(response.text, 'html.parser')
|
| 22 |
+
price_tag = soup.find('bg-quote', class_='value')
|
| 23 |
+
if price_tag:
|
| 24 |
+
return price_tag.get_text(strip=True)
|
| 25 |
+
return None
|
| 26 |
+
|
| 27 |
+
def get_historical_data(symbol: str, days=30):
|
| 28 |
+
end_date = datetime.now()
|
| 29 |
+
start_date = end_date - timedelta(days=days)
|
| 30 |
+
start_date_str = start_date.strftime('%m/%d/%Y 00:00:00')
|
| 31 |
+
end_date_str = end_date.strftime('%m/%d/%Y 23:59:59')
|
| 32 |
+
csv_url = (
|
| 33 |
+
f'https://www.marketwatch.com/investing/stock/{symbol}/downloaddatapartial'
|
| 34 |
+
f'?csvdownload=true&downloadpartial=false'
|
| 35 |
+
f'&startdate={start_date_str}&enddate={end_date_str}'
|
| 36 |
+
f'&frequency=p1d&newdates=false'
|
| 37 |
+
)
|
| 38 |
+
response = requests.get(csv_url, headers=HEADERS)
|
| 39 |
+
if response.status_code == 200:
|
| 40 |
+
try:
|
| 41 |
+
df = pd.read_csv(StringIO(response.text))
|
| 42 |
+
return df
|
| 43 |
+
except Exception:
|
| 44 |
+
return None
|
| 45 |
+
return None
|
| 46 |
+
|
| 47 |
+
def get_technical_analysis_docs():
|
| 48 |
+
return """
|
| 49 |
+
Technical Analysis: Core Concepts & Formulas
|
| 50 |
+
-------------------------------------------
|
| 51 |
+
- Market Action Discounts Everything: All known information is reflected in price.
|
| 52 |
+
- Prices Move in Trends: Uptrend, downtrend, or sideways movement.
|
| 53 |
+
- History Repeats Itself: Psychological patterns repeat.
|
| 54 |
+
|
| 55 |
+
Key Technical Indicators and Their Formulas:
|
| 56 |
+
-------------------------------------------
|
| 57 |
+
1. Simple Moving Average (SMA): SMA(time_period) = Sum(Price_t ... Price_{t-n}) / n
|
| 58 |
+
2. Exponential Moving Average (EMA): EMA_t = (Price_t * α) + EMA_{t-1} * (1 - α), where α = 2/(n+1)
|
| 59 |
+
3. Relative Strength Index (RSI): RSI = 100 - [100 / (1 + Avg Gain / Avg Loss)]
|
| 60 |
+
4. MACD (Moving Average Convergence Divergence): MACD Line = 12-period EMA - 26-period EMA; Signal Line = 9-period EMA of MACD Line; Histogram = MACD Line - Signal Line
|
| 61 |
+
5. Stochastic Oscillator (STOCH): Fast K = (Current Close - Lowest Low) / (Highest High - Lowest Low) * 100 over N periods; Slow K = 3-day SMA of Fast K; Slow D = 3-day SMA of Slow K
|
| 62 |
+
6. Momentum (MOM): MOM = Current Close - Close_N_days_ago
|
| 63 |
+
7. Rate of Change (ROC): ROC = [(Current Close - Prior Close) / Prior Close] * 100
|
| 64 |
+
8. Volume Weighted Average Price (VWAP): VWAP = Sum(Price * Volume) / Sum(Volume) over intraday period
|
| 65 |
+
9. Bollinger Bands: Middle Band = 20-day SMA; Upper Band = 20-day SMA + 2 * 20-day Standard Deviation; Lower Band = 20-day SMA - 2 * 20-day Standard Deviation
|
| 66 |
+
10. Ichimoku Cloud: Tenkan-sen = (9-period high + low)/2; Kijun-sen = (26-period high + low)/2; Senkou Span A = (Tenkan-sen + Kijun-sen)/2 shifted forward by 26; Senkou Span B = (52-period high + low)/2 shifted forward by 26; Chikou Span = Current close shifted back by 26 days
|
| 67 |
+
|
| 68 |
+
11. **Williams %R**:
|
| 69 |
+
%R = (Highest High - Close) / (Highest High - Lowest Low) * -100 over N periods
|
| 70 |
+
|
| 71 |
+
12. **Commodity Channel Index (CCI)**:
|
| 72 |
+
CCI = (Typical Price - 20-day SMA of TP) / (0.015 * Mean Deviation)
|
| 73 |
+
where Typical Price = (High + Low + Close) / 3
|
| 74 |
+
|
| 75 |
+
13. **Average Directional Index (ADX)**:
|
| 76 |
+
ADX = Smoothed average of DX values, which measure directional strength
|
| 77 |
+
|
| 78 |
+
14. **On-Balance Volume (OBV)**:
|
| 79 |
+
OBV = previous OBV + volume if close > previous close, else -volume
|
| 80 |
+
|
| 81 |
+
15. **Moving Average Convergence Divergence (MACD)**:
|
| 82 |
+
MACD Line = 12-day EMA - 26-day EMA
|
| 83 |
+
Signal Line = 9-day EMA of MACD Line
|
| 84 |
+
MACD Histogram = MACD Line - Signal Line
|
| 85 |
+
|
| 86 |
+
16. **Absolute Price Oscillator (APO)**:
|
| 87 |
+
APO = Fast EMA - Slow EMA
|
| 88 |
+
|
| 89 |
+
17. **Balance of Power (BOP)**:
|
| 90 |
+
BOP = (Close - Open) / (High - Low)
|
| 91 |
+
|
| 92 |
+
18. **Triple Exponential Moving Average (TEMA)**:
|
| 93 |
+
TEMA = (3 * EMA1) - (3 * EMA2) + EMA3
|
| 94 |
+
where EMA1 = fast EMA, EMA2 = slower EMA, etc.
|
| 95 |
+
|
| 96 |
+
19. **Double Exponential Moving Average (DEMA)**:
|
| 97 |
+
DEMA = 2*EMA1 - EMA2
|
| 98 |
+
|
| 99 |
+
20. **Kaufman Adaptive Moving Average (KAMA)**:
|
| 100 |
+
KAMA = prior KAMA + SC * (price - prior KAMA)
|
| 101 |
+
where SC = smoothing constant based on efficiency ratio
|
| 102 |
+
|
| 103 |
+
21. **Chaikin Money Flow (CMF)**:
|
| 104 |
+
MF Multiplier = [(Close - Low) - (High - Close)] / (High - Low)
|
| 105 |
+
MF Volume = MF Multiplier * Volume
|
| 106 |
+
CMF = Sum(MF Volume) / Sum(Volume) over N days
|
| 107 |
+
|
| 108 |
+
22. **Aroon Indicator**:
|
| 109 |
+
Aroon Up = ((N - Periods Since Highest Close) / N) * 100
|
| 110 |
+
Aroon Down = ((N - Periods Since Lowest Close) / N) * 100
|
| 111 |
+
|
| 112 |
+
23. **Parabolic SAR**:
|
| 113 |
+
SAR_t = SAR_{t-1} + AF * (EP - SAR_{t-1})
|
| 114 |
+
|
| 115 |
+
24. **Standard Deviation (Volatility)**:
|
| 116 |
+
σ = sqrt[1/N * Σ(Close_i - μ)^2]
|
| 117 |
+
|
| 118 |
+
25. **Candlestick Patterns**:
|
| 119 |
+
- Hammer, Shooting Star, Engulfing, Doji, Morning/Evening Star, etc.
|
| 120 |
+
"""
|
| 121 |
+
|
| 122 |
+
def analyze(symbol):
|
| 123 |
+
symbol = symbol.strip().lower()
|
| 124 |
+
current_price = get_current_price(symbol)
|
| 125 |
+
historical_df = get_historical_data(symbol, days=30)
|
| 126 |
+
if current_price is None or historical_df is None:
|
| 127 |
+
return "Could not retrieve data for this symbol. Try another."
|
| 128 |
+
historical_csv_snippet = historical_df.to_csv(index=False)
|
| 129 |
+
prompt = f"""
|
| 130 |
+
You are a financial LLM trained in technical analysis. Your task is to predict the next day's closing price for the stock symbol '{symbol.upper()}'.
|
| 131 |
+
|
| 132 |
+
The current stock price is approximately: ${current_price if current_price else 'N/A'}
|
| 133 |
+
|
| 134 |
+
Below is the historical OHLCV data for the last 10 days (CSV format):
|
| 135 |
+
{historical_csv_snippet if historical_csv_snippet else 'No historical data available.'}
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
**Technical Analysis Documentation:**
|
| 140 |
+
{get_technical_analysis_docs()}
|
| 141 |
+
|
| 142 |
+
**Instructions:**
|
| 143 |
+
You must perform the entire analysis in one go — do not ask for any further data or clarification.
|
| 144 |
+
Perform the full process:
|
| 145 |
+
1. Review the historical OHLCV data provided.
|
| 146 |
+
2. Perform a rigorous, step-by-step technical analysis using the full range of indicators.
|
| 147 |
+
3. Identify trends, chart patterns, volume analysis, risk management.
|
| 148 |
+
4. Predict the next day’s closing price.
|
| 149 |
+
5. Justify your prediction with detailed reasoning.
|
| 150 |
+
---
|
| 151 |
+
**Step-by-Step Analysis Plan:**
|
| 152 |
+
1. Data Review and Preparation
|
| 153 |
+
2. Chart and Trend Analysis
|
| 154 |
+
3. Apply Core Technical Indicators
|
| 155 |
+
4. Pattern Recognition
|
| 156 |
+
5. Advanced Analysis
|
| 157 |
+
6. Confirmation and Risk Management
|
| 158 |
+
7. Prediction and Justification
|
| 159 |
+
8. Review and Backtesting (Optional)
|
| 160 |
+
---
|
| 161 |
+
**Output Format:**
|
| 162 |
+
- Predicted Price for Next Day:
|
| 163 |
+
- Detailed Reasoning:
|
| 164 |
+
- Trend analysis and key levels
|
| 165 |
+
- Indicator values and interpretations
|
| 166 |
+
- Patterns identified
|
| 167 |
+
- Volume analysis
|
| 168 |
+
- Confidence level and uncertainty factors
|
| 169 |
+
- Additional insights or warnings
|
| 170 |
+
"""
|
| 171 |
+
client = OpenAI(
|
| 172 |
+
base_url="https://openrouter.ai/api/v1",
|
| 173 |
+
api_key=OPENROUTER_API_KEY,
|
| 174 |
+
)
|
| 175 |
+
completion = client.chat.completions.create(
|
| 176 |
+
model="google/gemma-3n-e4b-it:free",
|
| 177 |
+
messages=[{"role": "user", "content": prompt}]
|
| 178 |
+
)
|
| 179 |
+
return completion.choices[0].message.content
|
| 180 |
+
|
| 181 |
+
iface = gr.Interface(
|
| 182 |
+
fn=analyze,
|
| 183 |
+
inputs=gr.Textbox(label="Stock Symbol (e.g. AAPL, TSLA, QBTS)"),
|
| 184 |
+
outputs="text",
|
| 185 |
+
title="Stock Technical Analysis & Prediction",
|
| 186 |
+
description="Enter a stock symbol to get a technical analysis and next-day price prediction."
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
if __name__ == "__main__":
|
| 190 |
+
iface.launch()
|