Spaces:
Sleeping
Sleeping
import gradio as gr | |
import pandas as pd | |
from datetime import datetime, timedelta | |
import requests | |
import json | |
import os | |
def verify_api_key(): | |
api_key = os.environ.get('MISTRAL_API_KEY') | |
if not api_key: | |
return "ERROR: Mistral API key not found in environment variables" | |
return "API key found" | |
def fetch_stock_data(symbol): | |
try: | |
end_date = datetime.now() | |
start_date = end_date - timedelta(days=30) # Changed to 30 days | |
# Add .NS suffix for NSE stocks if not present | |
if not symbol.endswith('.NS') and not symbol.startswith('^'): | |
symbol = f"{symbol}.NS" | |
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}?period1={int(start_date.timestamp())}&period2={int(end_date.timestamp())}&interval=1d" | |
headers = { | |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' | |
} | |
response = requests.get(url, headers=headers) | |
data = response.json() | |
timestamps = data['chart']['result'][0]['timestamp'] | |
quote = data['chart']['result'][0]['indicators']['quote'][0] | |
df = pd.DataFrame({ | |
'Date': [datetime.fromtimestamp(ts).strftime('%Y-%m-%d') for ts in timestamps], | |
'Open': quote['open'], | |
'High': quote['high'], | |
'Low': quote['low'], | |
'Close': quote['close'], | |
'Volume': quote['volume'] | |
}) | |
numeric_columns = ['Open', 'High', 'Low', 'Close'] | |
df[numeric_columns] = df[numeric_columns].round(2) | |
return df | |
except Exception as e: | |
print(f"Error fetching data: {str(e)}") | |
return pd.DataFrame() | |
def get_swing_trade_analysis(df, symbol): | |
try: | |
api_key = os.environ.get('MISTRAL_API_KEY') | |
if not api_key: | |
return "Error: Mistral API key not found. Please add it to the environment variables." | |
# Get last 30 days of data | |
last_30_days = df.tail(30) | |
# Calculate current price and other metrics | |
current_price = last_30_days.iloc[-1]['Close'] | |
avg_volume = last_30_days['Volume'].mean() | |
price_change = ((current_price - last_30_days.iloc[0]['Close']) / last_30_days.iloc[0]['Close']) * 100 | |
# Format data for prompt | |
data_str = f"""Analyze the following stock data for {symbol} for swing trading suitability. | |
Current Price: {current_price} | |
30-Day Price Change: {price_change:.2f}% | |
Average Daily Volume: {avg_volume:,.0f} | |
Please provide a comprehensive swing trading analysis in the following format: | |
Price Action Analysis: | |
- Trend Analysis: | |
- Key Support Levels: | |
- Key Resistance Levels: | |
- Volume Analysis: | |
Swing Trading Suitability: | |
- Overall Rating (1-10): | |
- Risk Level (Low/Medium/High): | |
- Suggested Position Size: | |
- Recommended Holding Period: | |
Trading Setup (if suitable): | |
- Entry Strategy: | |
- Entry Price Range: | |
- Stop Loss: | |
- Target Prices (multiple levels): | |
- Risk/Reward Ratio: | |
Key Observations: | |
- List 3-4 critical points about price action and volume patterns | |
Last 30 days data: | |
""" | |
for _, row in last_30_days.iterrows(): | |
data_str += f"{row['Date']}: O:{row['Open']} H:{row['High']} L:{row['Low']} C:{row['Close']} V:{row['Volume']:,.0f}\n" | |
url = "https://api.mistral.ai/v1/chat/completions" | |
headers = { | |
"Content-Type": "application/json", | |
"Authorization": f"Bearer {api_key}" | |
} | |
data = { | |
"model": "mistral-small", | |
"messages": [ | |
{"role": "system", "content": "You are an experienced swing trader specializing in price action analysis. Provide detailed, actionable analysis focusing on price action patterns, volume analysis, and swing trading suitability. Be specific with numbers and levels."}, | |
{"role": "user", "content": data_str} | |
], | |
"temperature": 0.7, | |
"max_tokens": 1000 | |
} | |
response = requests.post(url, headers=headers, json=data) | |
if response.status_code == 200: | |
return response.json()['choices'][0]['message']['content'] | |
else: | |
return f"Error {response.status_code}: {response.text}" | |
except Exception as e: | |
return f"Error getting analysis: {str(e)}" | |
def analyze_stock(symbol): | |
api_status = verify_api_key() | |
if api_status.startswith("ERROR"): | |
return pd.DataFrame(), api_status | |
if not symbol: | |
return pd.DataFrame(), "Please enter a stock symbol" | |
df = fetch_stock_data(symbol) | |
if df.empty: | |
return df, f"Unable to fetch data for symbol: {symbol}" | |
analysis = get_swing_trade_analysis(df, symbol) | |
return df, analysis | |
# Create Gradio interface | |
with gr.Blocks() as demo: | |
with gr.Column(): | |
gr.Markdown("# Stock Swing Trading Analysis") | |
# Add input for stock symbol | |
stock_input = gr.Textbox( | |
label="Enter Stock Symbol (e.g., RELIANCE, INFY, TATAMOTORS, or ^NSEI for Nifty50)", | |
placeholder="Enter stock symbol...", | |
info="For NSE stocks, you can enter the symbol directly (e.g., RELIANCE). For indices, use ^ prefix (e.g., ^NSEI)" | |
) | |
# Add analyze button | |
analyze_btn = gr.Button("Analyze Stock", variant="primary") | |
# Add outputs | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("### Historical Data (Last 30 Days)") | |
output_table = gr.Dataframe( | |
headers=["Date", "Open", "High", "Low", "Close", "Volume"], | |
wrap=True | |
) | |
with gr.Column(scale=1): | |
gr.Markdown("### Swing Trading Analysis") | |
analysis_output = gr.Textbox( | |
label="Analysis Results", | |
lines=20, | |
elem_classes="analysis" | |
) | |
# Set up analyze button click event | |
analyze_btn.click( | |
fn=analyze_stock, | |
inputs=[stock_input], | |
outputs=[output_table, analysis_output], | |
) | |
# Launch the app with sharing enabled | |
demo.launch(share=True) |