Spaces:
Sleeping
Sleeping
File size: 18,230 Bytes
35cd772 605026d 35cd772 c7f8147 a919a08 35cd772 1f23e4b 35cd772 1e96b75 036e101 35cd772 5bb2b91 35cd772 5bb2b91 35cd772 5bb2b91 35cd772 1e96b75 5bb2b91 35cd772 5bb2b91 35cd772 5bb2b91 35cd772 1e96b75 35cd772 5bb2b91 35cd772 1e96b75 35cd772 605026d 5bb2b91 066c51a 5bb2b91 4a2c8a4 5bb2b91 ad0055f 5bb2b91 ad0055f 5bb2b91 ad0055f 5bb2b91 ad0055f 5bb2b91 cafa384 017f01d 5bb2b91 9411d73 f7d0a84 9411d73 35cd772 f7d0a84 9411d73 dc363fb 35cd772 4f13da0 35cd772 1c0b871 9411d73 331592e 17f9994 cb33f24 17f9994 0bdd1c4 cb33f24 0bdd1c4 cb33f24 17f9994 cb33f24 17f9994 35cd772 331592e e1a4603 35cd772 17f9994 331592e 17f9994 614511d 35cd772 d41207b 29c390a a5864f4 017f01d d41207b ec00f29 77dfae0 d41207b 35cd772 17f9994 614511d 17f9994 35cd772 17f9994 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
import os
import requests
from typing import Dict, Any
import snowflake.connector
from openai import OpenAI
import gradio as gr
import time
from datetime import datetime
from io import BytesIO
import base64
import matplotlib.pyplot as plt
import pandas as pd
def get_financial_data(ticker: str, api_key: str, period: str = 'annual') -> Dict[str, Any]:
base_url = "https://financialmodelingprep.com/api/v3/"
endpoints = {
"profile": f"profile/{ticker}?apikey={api_key}",
"balance_sheet": f"balance-sheet-statement/{ticker}?period={period}&apikey={api_key}",
"income_statement": f"income-statement/{ticker}?period={period}&apikey={api_key}"
}
results = {}
for key, endpoint in endpoints.items():
url = base_url + endpoint
response = requests.get(url)
if response.status_code == 200:
data = response.json()
if data:
if key == "profile":
results[key] = data[0]
elif key == "balance_sheet":
results[key] = data[0] # Get the most recent balance sheet statement
elif key == "income_statement":
results[key] = data[0] # Get the most recent income statement
else:
results[key] = None
else:
raise Exception(f"Failed to fetch data from {key} endpoint for ticker {ticker}. HTTP Status Code: {response.status_code}")
return results
def get_proprietary_indicators(ticker: str) -> str:
connection = snowflake.connector.connect(
user=os.getenv('SNOWFLAKE_USER'),
password=os.getenv('SNOWFLAKE_PASSWORD'),
account=os.getenv('SNOWFLAKE_ACCOUNT'),
warehouse=os.getenv('SNOWFLAKE_WAREHOUSE'),
database=os.getenv('SNOWFLAKE_DATABASE')
)
query = f"""
SELECT prompt
FROM researchdata.TS_INDICATORS_FOR_GPT_PROMPT
WHERE SYMBOL = '{ticker}'
"""
cursor = connection.cursor()
cursor.execute(query)
result = cursor.fetchone()
connection.close()
if result:
return result[0]
else:
return "No proprietary indicators available for this ticker."
def fetch_news(ticker: str, api_key: str) -> str:
url = f'https://financialmodelingprep.com/api/v3/stock_news?page=0&tickers={ticker}&apikey={api_key}'
response = requests.get(url)
if response.status_code == 200:
news_data = response.json()
if news_data:
news_summary = '\n\nRecent News Articles:\n'
for article in news_data[:5]: # Limit to the 5 most recent articles
news_summary += f"Publish Date: {article['publishedDate']}\nTitle: {article['title']}\nSummary:{article['text']}\n\n"
return news_summary
else:
return "No recent news articles found."
else:
return "Failed to fetch news articles."
def format_for_gpt_prompt(financial_data: Dict[str, Any], proprietary_indicators: str, news_data: str) -> str:
profile = financial_data.get('profile', {})
balance_sheet = financial_data.get('balance_sheet', {})
income_statement = financial_data.get('income_statement', {})
company_name = profile.get('companyName', 'N/A')
company_description = profile.get('description', 'N/A')
ticker = profile.get('symbol', 'N/A')
market_cap = profile.get('mktCap', 'N/A')
ceo = profile.get('ceo', 'N/A')
beta = profile.get('beta', 'N/A')
financial_data_str = f"""
Balance Sheet:
Total Assets: {balance_sheet.get('totalAssets', 'N/A')}
Total Liabilities: {balance_sheet.get('totalLiabilities', 'N/A')}
Total Equity: {balance_sheet.get('totalEquity', 'N/A')}
Cash and Cash Equivalents: {balance_sheet.get('cashAndCashEquivalents', 'N/A')}
Cash and Short Term Investments: {balance_sheet.get('cashAndShortTermInvestments', 'N/A')}
Inventory: {balance_sheet.get('inventory', 'N/A')}
Net Receivables: {balance_sheet.get('netReceivables', 'N/A')}
Total Current Assets: {balance_sheet.get('totalCurrentAssets', 'N/A')}
Total Current Liabilities: {balance_sheet.get('totalCurrentLiabilities', 'N/A')}
Long Term Debt: {balance_sheet.get('longTermDebt', 'N/A')}
Short Term Debt: {balance_sheet.get('shortTermDebt', 'N/A')}
Total Debt: {balance_sheet.get('totalDebt', 'N/A')}
Property, Plant, and Equipment Net: {balance_sheet.get('propertyPlantEquipmentNet', 'N/A')}
Deferred Revenue: {balance_sheet.get('deferredRevenue', 'N/A')}
Accumulated Other Comprehensive Income Loss: {balance_sheet.get('accumulatedOtherComprehensiveIncomeLoss', 'N/A')}
Retained Earnings: {balance_sheet.get('retainedEarnings', 'N/A')}
Total Non-Current Assets: {balance_sheet.get('totalNonCurrentAssets', 'N/A')}
Total Non-Current Liabilities: {balance_sheet.get('totalNonCurrentLiabilities', 'N/A')}
Goodwill and Intangible Assets: {balance_sheet.get('goodwillAndIntangibleAssets', 'N/A')}
Income Statement:
Revenue: {income_statement.get('revenue', 'N/A')}
Cost of Revenue: {income_statement.get('costOfRevenue', 'N/A')}
Gross Profit: {income_statement.get('grossProfit', 'N/A')}
Gross Profit Ratio: {income_statement.get('grossProfitRatio', 'N/A')}
Operating Income: {income_statement.get('operatingIncome', 'N/A')}
Operating Income Ratio: {income_statement.get('operatingIncomeRatio', 'N/A')}
Net Income: {income_statement.get('netIncome', 'N/A')}
Net Income Ratio: {income_statement.get('netIncomeRatio', 'N/A')}
EBITDA: {income_statement.get('ebitda', 'N/A')}
EBITDA Ratio: {income_statement.get('ebitdaratio', 'N/A')}
Earnings Per Share (EPS): {income_statement.get('eps', 'N/A')}
Diluted EPS: {income_statement.get('epsdiluted', 'N/A')}
Cost and Expenses: {income_statement.get('costAndExpenses', 'N/A')}
Depreciation and Amortization: {income_statement.get('depreciationAndAmortization', 'N/A')}
Income Before Tax: {income_statement.get('incomeBeforeTax', 'N/A')}
Income Before Tax Ratio: {income_statement.get('incomeBeforeTaxRatio', 'N/A')}
Income Tax Expense: {income_statement.get('incomeTaxExpense', 'N/A')}
Operating Expenses: {income_statement.get('operatingExpenses', 'N/A')}
Research and Development Expenses: {income_statement.get('researchAndDevelopmentExpenses', 'N/A')}
Selling, General, and Administrative Expenses: {income_statement.get('sellingGeneralAndAdministrativeExpenses', 'N/A')}
Total Other Income Expenses Net: {income_statement.get('totalOtherIncomeExpensesNet', 'N/A')}
Weighted Average Shares Outstanding: {income_statement.get('weightedAverageShsOut', 'N/A')}
Weighted Average Shares Outstanding Diluted: {income_statement.get('weightedAverageShsOutDil', 'N/A')}
"""
prompt = f"""
Here is the profile of the company you will be analyzing:
<company>
Name: {company_name} ({ticker})
Description: {company_description}
Market Cap: {market_cap}
CEO: {ceo}
Beta: {beta}
</company>
Please carefully review this background information on the company.
Next, here is the most recent quarter's balance sheet and income statement data for the company:
<financial_data>
{financial_data_str}
</financial_data>
Next, here are some of the proprietary TradeSmith indicators for the company:
<proprietary_indicators>
{proprietary_indicators}
</proprietary_indicators>
Next, here are some recent news articles about the company:
<news_articles>
{news_data}
</news_articles>
<analysis>
Provide your analysis of the company profile, financial data, proprietary TradeSmith indicators, and recent news. Show your analytical thought process.
</analysis>
<prediction>
Considering everything, what prediction would you make for this stock's return over the next 21 trading days? If TradeSmith's Predictive Alpha projection was told to you, use that as your prediction, and make sure your reasoning aligns with the prediction. Otherwise, make your own prediction based on the information you analyzed.
</prediction>
Remember, your role is to be an expert stock analyst. Explain your reasoning so that investors can understand the key factors driving your recommendation. Assume you are talking to a group of readers, not to an individual, to comply with legal's requirement of not giving out personalized advice. At the end, always disclaim something along the lines of "investing and trading is risky..."
"""
return prompt
def generate_gpt_prompt(ticker: str, api_key: str) -> str:
financial_data = get_financial_data(ticker, api_key)
proprietary_indicators = get_proprietary_indicators(ticker)
news_data = fetch_news(ticker, api_key)
return format_for_gpt_prompt(financial_data, proprietary_indicators, news_data)
def run_gpt_model(prompt: str, api_key: str) -> str:
openai_client = OpenAI(api_key = api_key)
system_prompt = """
You are a highly experienced stock analyst with deep knowledge of TradeSmith and InvestorPlace products and services. You assist subscribers of these platforms by providing comprehensive stock analyses. Ensure your output is clear, concise, and formatted for easy reading with line breaks after each sentence. The analysis should be structured as follows:
[Company Description]:
Provide a brief overview of the company in 2-3 sentences.
[TradeSmith Indicator Analysis]:
Incorporate relevant TradeSmith indicators, explaining what they suggest about the stock's performance and potential. Use proprietary indicators effectively to add value to the analysis. Use bullet points, and for each point, explain why it's worth noting. If any billionaires hold the stock, name them. If the Predictive Alpha prediction is told to you, don't talk about it here, use it as your prediction in the following Prediction & Analysis section.
[News Analysis]:
Summarize recent news articles or reports related to the company. Discuss any significant events or developments that could impact the stock's performance. Use bullet points, and for each point, explain why it's worth noting.
[Income Statement Analysis]:
Analyze key figures from the company's income statement, such as revenue, expenses, and net income. Highlight trends and significant changes. Use bullet points, and for each point, explain why it's worth noting.
[Balance Sheet Analysis]:
Examine important elements from the balance sheet, focusing on assets, liabilities, and shareholders' equity. Discuss the company's financial health and stability. Use bullet points, and for each point, explain why it's worth noting.
[Prediction & Reasoning]:
Provide a well-reasoned prediction for the stock's future 21 day performance. If a Predictive Alpha prediction was provided, use that as your prediction, supported by your analysis. Offer actionable recommendations based on your insights.
Make sure each section is thorough yet concise, providing valuable insights for the subscriber. Only touch on the details you deem important. Your output should look professionally formatted and work well with gradio's markup output.
Finally, it is critically important that you comply with the legal guideline of not providing personalized financial advice to individuals.
"""
system = {
"role":"system",
"content": (system_prompt)
}
user = {
"role":"user",
"content":prompt
}
response = openai_client.chat.completions.create(
model="gpt-4o", # or another model
messages = [system,user],
max_tokens=1500,
temperature=0.7,
stream=True
)
collected_chunks = ""
for chunk in response:
chunk_content = chunk.choices[0].delta.content or ""
if chunk_content:
yield chunk_content
#time.sleep(0.01)
def plot_price_chart(ticker: str):
# Establishing connection to Snowflake
connection = snowflake.connector.connect(
user=os.getenv('SNOWFLAKE_USER'),
password=os.getenv('SNOWFLAKE_PASSWORD'),
account=os.getenv('SNOWFLAKE_ACCOUNT'),
warehouse=os.getenv('SNOWFLAKE_WAREHOUSE'),
database=os.getenv('SNOWFLAKE_DATABASE')
)
cursor = connection.cursor()
# Function to get historical price data
def get_historical_price_data(ticker):
query = f"""
select s.symbol,
sd.TRADEDATE,
sd.TRADEADJCLOSE
from HISTORICALDATANEW.SYMBOL_SVIEW s
join HISTORICALDATANEW.SYMBOLTYPES_SVIEW st on s.SYMBOLTYPEID = st.SYMBOLTYPEID
join HISTORICALDATANEW.STOCKDATA_SVIEW sd on s.SYMBOLID = sd.SYMBOLID
where st.name in ('Common stock','ETF')
and case when s.ISDUPLICATE then 1 else 0 end = 0
and s.EXCHANGEID in (1,8)
and s.SYMBOL = '{ticker}'
qualify row_number() over (partition by s.SYMBOLID order by TRADEDATE desc) <= 50
order by TRADEDATE;
"""
historical_price_data = cursor.execute(query).fetch_pandas_all()
return historical_price_data
# Function to get predicted return data
def get_predicted_return_data(ticker):
query = f"""
select s.SYMBOL,
pa.PREDICTEDTRADEDATE,
pa.PREDICTEDRETURN
from RESEARCHDATA.PREDICTIVEALPHAHISTORICALVALUES_SVIEW pa
join HISTORICALDATANEW.SYMBOL_SVIEW s on s.SYMBOLID = pa.SYMBOLID
where pa.PREDICTEDPERIOD = 21
and s.SYMBOL = '{ticker}'
qualify row_number() over (partition by pa.SYMBOLID order by TRADEDATE desc) = 1;
"""
predicted_return_data = cursor.execute(query).fetch_pandas_all()
return predicted_return_data
historical_data = get_historical_price_data(ticker)
predicted_data = get_predicted_return_data(ticker)
# Extract the relevant data
historical_dates = pd.to_datetime(historical_data['TRADEDATE'])
historical_prices = historical_data['TRADEADJCLOSE'].astype(float)
last_known_date = historical_dates.iloc[-1]
last_known_price = historical_prices.iloc[-1]
predicted_date = pd.to_datetime(predicted_data['PREDICTEDTRADEDATE'].iloc[0])
predicted_return = float(predicted_data['PREDICTEDRETURN'].iloc[0])
predicted_price = last_known_price * (1 + predicted_return)
# Plot the data
plt.figure(figsize=(12, 6)) # Increase figure size to give more space for annotations
plt.plot(historical_dates, historical_prices, label='Historical Prices', marker='o')
plt.axvline(x=last_known_date, color='gray', linestyle='--', label='Last Known Date')
plt.plot([last_known_date, predicted_date], [last_known_price, predicted_price], 'r--', label='Predicted Price')
# Adding gap for 21 trading days (assuming 5 trading days per week)
gap_dates = pd.date_range(start=last_known_date, periods=22, freq='B')[-1]
plt.axvline(x=gap_dates, color='blue', linestyle='--', label='21 Trading Days Gap')
# Annotations
plt.annotate(f'Last Known Price: {last_known_price:.2f}',
xy=(last_known_date, last_known_price),
xytext=(last_known_date, last_known_price * 1.05),
arrowprops=dict(facecolor='black', arrowstyle='->'),
bbox=dict(boxstyle='round,pad=0.5', edgecolor='black', facecolor='white'))
plt.annotate(f'Predicted Price: {predicted_price:.2f}\nPredicted Return: {predicted_return:.2%}',
xy=(predicted_date, predicted_price),
xytext=(predicted_date, predicted_price * 1.05),
arrowprops=dict(facecolor='red', arrowstyle='->'),
bbox=dict(boxstyle='round,pad=0.5', edgecolor='red', facecolor='white'))
plt.xlabel('Date')
plt.ylabel('Price')
plt.title(f'{ticker} Price Chart with Predicted Price')
plt.legend()
plt.grid(True)
# Adjust limits to ensure annotations fit
plt.ylim(bottom=min(historical_prices) * 0.95, top=max(historical_prices) * 1.1)
plt.xlim(left=min(historical_dates), right=predicted_date + pd.Timedelta(days=10))
# Save plot to a bytes buffer
buf = BytesIO()
plt.savefig(buf, format="png")
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode("utf-8")
buf.close()
return f'<img src="data:image/png;base64,{img_str}" alt="Price Chart">'
def analyze_stock(ticker: str):
ticker = ticker.upper()
fmp_api_key = os.getenv('FMP_API_KEY')
openai_api_key = os.getenv('OPENAI_API_KEY')
prompt = generate_gpt_prompt(ticker, fmp_api_key)
yield prompt, "", "" # Initially yield the prompt with empty analysis and chart response
analysis_chunks = []
for analysis_chunk in run_gpt_model(prompt, openai_api_key):
analysis_chunks.append(analysis_chunk)
yield "".join(analysis_chunks), prompt, "" # Stream the accumulated analysis chunks
# Generate the price chart after the analysis
price_chart_html = plot_price_chart(ticker)
yield "".join(analysis_chunks),price_chart_html, prompt
description = """We gave Ann-E a name, but not a personality. It's time to change that!
Imagine entering a ticker on the TradeSmith site, going to the Predictive Alpha widget, and getting a stock analysis from Ann-E to go along with the prediction.
Currently, the analysis is based on company profile information, recent news, the most recent quarter's balance sheet and income statements, and TradeSmith proprietary indicators.
This demonstration shows just a simple use case for building out a proprietary Alta Large Language Model (LLM).
Future vision includes interactive model, fine-tuned on Alta content and indicators, that help our subscribers and keep them engaged on the site.
The possibilities are endless!
Note: We can control outputs to meet legal requirements.
"""
# Gradio Interface
iface = gr.Interface(
fn=analyze_stock,
inputs=gr.Textbox(label='Enter a Ticker', value='AAPL'),
outputs=[
gr.Markdown(label='Ann-E Response'),
gr.HTML(label='Price Chart'),
gr.Textbox(label='Prompt for Model (behind the scenes).')
],
title="Demo: Predictive Alpha + Stock Analysis GPT Model",
description=description
)
if __name__ == "__main__":
iface.launch() |