Spaces:
Sleeping
Sleeping
import requests | |
from bs4 import BeautifulSoup | |
import pandas as pd | |
from io import StringIO | |
from datetime import datetime, timedelta | |
from langchain.tools import tool | |
from langchain.agents import initialize_agent, Tool | |
from langchain_openai import ChatOpenAI | |
# === Configuration === | |
OPENROUTER_API_KEY = "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" | |
HEADERS = { | |
'User-Agent': ( | |
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' | |
'AppleWebKit/537.36 (KHTML, like Gecko) ' | |
'Chrome/124.0.0.0 Safari/537.36' | |
), | |
'Accept': ( | |
'text/html,application/xhtml+xml,application/xml;' | |
'q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8' | |
), | |
'Accept-Language': 'en-US,en;q=0.9', | |
'Referer': 'https://www.google.com/', | |
'Connection': 'keep-alive', | |
'Cache-Control': 'max-age=0', | |
'Upgrade-Insecure-Requests': '1' | |
} | |
def get_current_price(symbol: str) -> str: | |
"""Get the current price for a stock symbol (e.g., 'AAPL').""" | |
url = f'https://www.marketwatch.com/investing/stock/{symbol}' | |
response = requests.get(url, headers=HEADERS) | |
if response.status_code == 200: | |
soup = BeautifulSoup(response.text, 'html.parser') | |
price_tag = soup.find('bg-quote', class_='value') | |
if price_tag: | |
price = price_tag.get_text(strip=True) | |
return f"{symbol.upper()} current price: ${price} (from MarketWatch)" | |
else: | |
return "Stock price not found." | |
else: | |
return f"Failed to retrieve stock page. Status code: {response.status_code}" | |
def get_historical_data(symbol: str, days: int = 5000) -> str: | |
"""Get the last N days of historical OHLCV data for a stock symbol as CSV.""" | |
end_date = datetime.now() | |
start_date = end_date - timedelta(days=days) | |
start_date_str = start_date.strftime('%m/%d/%Y 00:00:00') | |
end_date_str = end_date.strftime('%m/%d/%Y 23:59:59') | |
csv_url = ( | |
f'https://www.marketwatch.com/investing/stock/{symbol}/downloaddatapartial' | |
f'?csvdownload=true&downloadpartial=false' | |
f'&startdate={start_date_str}&enddate={end_date_str}' | |
f'&frequency=p1d&newdates=false' | |
) | |
response = requests.get(csv_url, headers=HEADERS) | |
if response.status_code == 200: | |
try: | |
df = pd.read_csv(StringIO(response.text)) | |
return f"Historical data for {symbol.upper()} (from MarketWatch):\n" + df.head(10).to_csv(index=False) | |
except Exception as e: | |
return f"Failed to parse CSV data: {e}" | |
else: | |
return f"Failed to download historical data. Status code: {response.status_code}" | |
def get_technical_analysis_docs(_: str = "") -> str: | |
"""Get documentation for technical analysis indicators.""" | |
return """ | |
Technical Analysis: Core Concepts & Formulas | |
------------------------------------------- | |
- Market Action Discounts Everything: All known information is reflected in price. | |
- Prices Move in Trends: Uptrend, downtrend, or sideways movement. | |
- History Repeats Itself: Psychological patterns repeat. | |
Key Technical Indicators and Their Formulas: | |
------------------------------------------- | |
1. Simple Moving Average (SMA): SMA(time_period) = Sum(Price_t ... Price_{t-n}) / n | |
2. Exponential Moving Average (EMA): EMA_t = (Price_t * α) + EMA_{t-1} * (1 - α), where α = 2/(n+1) | |
3. Relative Strength Index (RSI): RSI = 100 - [100 / (1 + Avg Gain / Avg Loss)] | |
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 | |
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 | |
6. Momentum (MOM): MOM = Current Close - Close_N_days_ago | |
7. Rate of Change (ROC): ROC = [(Current Close - Prior Close) / Prior Close] * 100 | |
8. Volume Weighted Average Price (VWAP): VWAP = Sum(Price * Volume) / Sum(Volume) over intraday period | |
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 | |
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 | |
11. **Williams %R**: | |
%R = (Highest High - Close) / (Highest High - Lowest Low) * -100 over N periods | |
12. **Commodity Channel Index (CCI)**: | |
CCI = (Typical Price - 20-day SMA of TP) / (0.015 * Mean Deviation) | |
where Typical Price = (High + Low + Close) / 3 | |
13. **Average Directional Index (ADX)**: | |
ADX = Smoothed average of DX values, which measure directional strength | |
14. **On-Balance Volume (OBV)**: | |
OBV = previous OBV + volume if close > previous close, else -volume | |
15. **Moving Average Convergence Divergence (MACD)**: | |
MACD Line = 12-day EMA - 26-day EMA | |
Signal Line = 9-day EMA of MACD Line | |
MACD Histogram = MACD Line - Signal Line | |
16. **Absolute Price Oscillator (APO)**: | |
APO = Fast EMA - Slow EMA | |
17. **Balance of Power (BOP)**: | |
BOP = (Close - Open) / (High - Low) | |
18. **Triple Exponential Moving Average (TEMA)**: | |
TEMA = (3 * EMA1) - (3 * EMA2) + EMA3 | |
where EMA1 = fast EMA, EMA2 = slower EMA, etc. | |
19. **Double Exponential Moving Average (DEMA)**: | |
DEMA = 2*EMA1 - EMA2 | |
20. **Kaufman Adaptive Moving Average (KAMA)**: | |
KAMA = prior KAMA + SC * (price - prior KAMA) | |
where SC = smoothing constant based on efficiency ratio | |
21. **Chaikin Money Flow (CMF)**: | |
MF Multiplier = [(Close - Low) - (High - Close)] / (High - Low) | |
MF Volume = MF Multiplier * Volume | |
CMF = Sum(MF Volume) / Sum(Volume) over N days | |
22. **Aroon Indicator**: | |
Aroon Up = ((N - Periods Since Highest Close) / N) * 100 | |
Aroon Down = ((N - Periods Since Lowest Close) / N) * 100 | |
23. **Parabolic SAR**: | |
SAR_t = SAR_{t-1} + AF * (EP - SAR_{t-1}) | |
24. **Standard Deviation (Volatility)**: | |
σ = sqrt[1/N * Σ(Close_i - μ)^2] | |
25. **Candlestick Patterns**: | |
- Hammer, Shooting Star, Engulfing, Doji, Morning/Evening Star, etc. | |
""" | |
tools = [ | |
Tool.from_function( | |
get_current_price, | |
name="GetCurrentPrice", | |
description="Get the current price for a stock symbol (e.g., AAPL)" | |
), | |
Tool.from_function( | |
get_historical_data, | |
name="GetHistoricalData", | |
description="Get the last N days of historical OHLCV data for a stock symbol as CSV" | |
), | |
Tool.from_function( | |
get_technical_analysis_docs, | |
name="GetTechnicalAnalysisDocs", | |
description="Provide documentation for technical analysis indicators" | |
) | |
] | |
llm = ChatOpenAI( | |
openai_api_key=OPENROUTER_API_KEY, | |
openai_api_base="https://openrouter.ai/api/v1", | |
model_name="google/gemma-3n-e4b-it:free" | |
) | |
agent = initialize_agent( | |
tools, | |
llm, | |
agent="zero-shot-react-description", | |
verbose=True # This will show all reasoning and tool usage! | |
) | |
if __name__ == "__main__": | |
print("Welcome to the Stock Analysis Agent!") | |
print("Ask anything about stocks, technical analysis, or predictions.") | |
print("Type 'exit' to quit.") | |
while True: | |
user_input = input("\nYour question: ") | |
if user_input.lower() in ["exit", "quit"]: | |
print("Goodbye!") | |
break | |
result = agent.run(user_input) | |
print("\nAgent's answer:\n", result) | |