Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,7 +14,7 @@ def verify_api_key():
|
|
| 14 |
def fetch_stock_data(symbol):
|
| 15 |
try:
|
| 16 |
end_date = datetime.now()
|
| 17 |
-
start_date = end_date - timedelta(days=10)
|
| 18 |
|
| 19 |
# Handle different market indexes
|
| 20 |
index_mapping = {
|
|
@@ -24,15 +24,34 @@ def fetch_stock_data(symbol):
|
|
| 24 |
'FINNIFTY': 'NIFTY_FIN_SERVICE.NS'
|
| 25 |
}
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
if symbol.upper() in index_mapping:
|
| 28 |
symbol = index_mapping[symbol.upper()]
|
| 29 |
elif not symbol.endswith('.NS') and not symbol.startswith('^'):
|
| 30 |
symbol = f"{symbol}.NS"
|
| 31 |
|
|
|
|
| 32 |
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}?period1={int(start_date.timestamp())}&period2={int(end_date.timestamp())}&interval=1d"
|
| 33 |
|
| 34 |
headers = {
|
| 35 |
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
}
|
| 37 |
|
| 38 |
response = requests.get(url, headers=headers)
|
|
@@ -51,9 +70,67 @@ def fetch_stock_data(symbol):
|
|
| 51 |
numeric_columns = ['Open', 'High', 'Low', 'Close']
|
| 52 |
df[numeric_columns] = df[numeric_columns].round(2)
|
| 53 |
df = df.reset_index()
|
| 54 |
-
df.index = df.index + 1
|
| 55 |
df = df.drop('index', axis=1)
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
return df
|
| 58 |
except Exception as e:
|
| 59 |
print(f"Error fetching data: {str(e)}")
|
|
@@ -66,16 +143,37 @@ def get_swing_trade_analysis(df, symbol):
|
|
| 66 |
return "Error: Mistral API key not found. Please add it to the environment variables."
|
| 67 |
|
| 68 |
# Get last 10 days of data
|
| 69 |
-
last_10_days = df.tail(10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
# Format data for prompt
|
| 72 |
data_str = f"""This is the last 10 days data for {symbol} index:
|
| 73 |
Open High Low Close
|
| 74 |
"""
|
| 75 |
-
for _, row in last_10_days.iterrows():
|
| 76 |
data_str += f"{row['Open']}\t{row['High']}\t{row['Low']}\t{row['Close']}\n"
|
| 77 |
|
| 78 |
-
data_str +=
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
url = "https://api.mistral.ai/v1/chat/completions"
|
| 81 |
|
|
@@ -87,24 +185,29 @@ Open High Low Close
|
|
| 87 |
data = {
|
| 88 |
"model": "mistral-small",
|
| 89 |
"messages": [
|
| 90 |
-
{"role": "system", "content": """You are a
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
-
|
| 93 |
-
-
|
| 94 |
-
-
|
| 95 |
-
-
|
| 96 |
|
| 97 |
-
|
| 98 |
-
-
|
| 99 |
-
-
|
| 100 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
-
|
| 103 |
-
- Recent swing highs and lows
|
| 104 |
-
- Key price levels where market reversed
|
| 105 |
-
- Areas of price rejection
|
| 106 |
-
|
| 107 |
-
Do not mention any technical indicators, moving averages, or oscillators. Pure price action only."""},
|
| 108 |
{"role": "user", "content": data_str}
|
| 109 |
],
|
| 110 |
"temperature": 0.7,
|
|
|
|
| 14 |
def fetch_stock_data(symbol):
|
| 15 |
try:
|
| 16 |
end_date = datetime.now()
|
| 17 |
+
start_date = end_date - timedelta(days=10)
|
| 18 |
|
| 19 |
# Handle different market indexes
|
| 20 |
index_mapping = {
|
|
|
|
| 24 |
'FINNIFTY': 'NIFTY_FIN_SERVICE.NS'
|
| 25 |
}
|
| 26 |
|
| 27 |
+
# NSE option chain URLs
|
| 28 |
+
nse_option_urls = {
|
| 29 |
+
'NIFTY50': 'https://www.nseindia.com/api/option-chain-indices?symbol=NIFTY',
|
| 30 |
+
'BANKNIFTY': 'https://www.nseindia.com/api/option-chain-indices?symbol=BANKNIFTY',
|
| 31 |
+
'FINNIFTY': 'https://www.nseindia.com/api/option-chain-indices?symbol=FINNIFTY'
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# Historical options data URLs
|
| 35 |
+
historical_options_urls = {
|
| 36 |
+
'NIFTY50': 'https://www.nseindia.com/api/historical/fo/derivatives?',
|
| 37 |
+
'BANKNIFTY': 'https://www.nseindia.com/api/historical/fo/derivatives?',
|
| 38 |
+
'FINNIFTY': 'https://www.nseindia.com/api/historical/fo/derivatives?'
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
if symbol.upper() in index_mapping:
|
| 42 |
symbol = index_mapping[symbol.upper()]
|
| 43 |
elif not symbol.endswith('.NS') and not symbol.startswith('^'):
|
| 44 |
symbol = f"{symbol}.NS"
|
| 45 |
|
| 46 |
+
# Fetch price data
|
| 47 |
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}?period1={int(start_date.timestamp())}&period2={int(end_date.timestamp())}&interval=1d"
|
| 48 |
|
| 49 |
headers = {
|
| 50 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 51 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
| 52 |
+
'Accept-Language': 'en-US,en;q=0.5',
|
| 53 |
+
'Accept-Encoding': 'gzip, deflate, br',
|
| 54 |
+
'Connection': 'keep-alive',
|
| 55 |
}
|
| 56 |
|
| 57 |
response = requests.get(url, headers=headers)
|
|
|
|
| 70 |
numeric_columns = ['Open', 'High', 'Low', 'Close']
|
| 71 |
df[numeric_columns] = df[numeric_columns].round(2)
|
| 72 |
df = df.reset_index()
|
| 73 |
+
df.index = df.index + 1
|
| 74 |
df = df.drop('index', axis=1)
|
| 75 |
|
| 76 |
+
# Try to fetch option chain and historical data
|
| 77 |
+
options_data = {}
|
| 78 |
+
orig_symbol = next((k for k, v in index_mapping.items() if v == symbol), None)
|
| 79 |
+
if orig_symbol in nse_option_urls:
|
| 80 |
+
try:
|
| 81 |
+
# First get the cookie
|
| 82 |
+
session = requests.Session()
|
| 83 |
+
session.get("https://www.nseindia.com/get-quotes/derivatives?symbol=" + orig_symbol, headers=headers)
|
| 84 |
+
cookies = session.cookies.get_dict()
|
| 85 |
+
|
| 86 |
+
# Then fetch option chain data
|
| 87 |
+
option_headers = headers.copy()
|
| 88 |
+
option_headers['Cookie'] = '; '.join([f"{k}={v}" for k, v in cookies.items()])
|
| 89 |
+
|
| 90 |
+
option_response = session.get(nse_option_urls[orig_symbol], headers=option_headers)
|
| 91 |
+
if option_response.status_code == 200:
|
| 92 |
+
option_data = option_response.json()
|
| 93 |
+
current_price = df.iloc[-1]['Close']
|
| 94 |
+
atm_strike = round(current_price / 50) * 50 # Round to nearest 50 for NIFTY
|
| 95 |
+
if orig_symbol == 'BANKNIFTY':
|
| 96 |
+
atm_strike = round(current_price / 100) * 100 # Round to nearest 100 for BANKNIFTY
|
| 97 |
+
|
| 98 |
+
# Get strikes near current price
|
| 99 |
+
strikes = [strike for strike in option_data['records']['data']
|
| 100 |
+
if abs(strike['strikePrice'] - current_price) <= 1000]
|
| 101 |
+
|
| 102 |
+
# Store strike prices and their details
|
| 103 |
+
for strike in strikes:
|
| 104 |
+
strike_price = strike['strikePrice']
|
| 105 |
+
if 'CE' in strike and 'PE' in strike:
|
| 106 |
+
options_data[strike_price] = {
|
| 107 |
+
'CE': {
|
| 108 |
+
'OI': strike['CE'].get('openInterest', 0),
|
| 109 |
+
'Volume': strike['CE'].get('totalTradedVolume', 0),
|
| 110 |
+
'LTP': strike['CE'].get('lastPrice', 0)
|
| 111 |
+
},
|
| 112 |
+
'PE': {
|
| 113 |
+
'OI': strike['PE'].get('openInterest', 0),
|
| 114 |
+
'Volume': strike['PE'].get('totalTradedVolume', 0),
|
| 115 |
+
'LTP': strike['PE'].get('lastPrice', 0)
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
# Sort strikes by total OI (CE + PE) to find strikes with highest interest
|
| 120 |
+
sorted_strikes = sorted(options_data.items(),
|
| 121 |
+
key=lambda x: (x[1]['CE']['OI'] + x[1]['PE']['OI']),
|
| 122 |
+
reverse=True)
|
| 123 |
+
|
| 124 |
+
# Store top 5 strikes by OI
|
| 125 |
+
top_strikes = sorted_strikes[:5]
|
| 126 |
+
|
| 127 |
+
df.attrs['options_data'] = options_data
|
| 128 |
+
df.attrs['top_strikes'] = top_strikes
|
| 129 |
+
df.attrs['atm_strike'] = atm_strike
|
| 130 |
+
|
| 131 |
+
except Exception as e:
|
| 132 |
+
print(f"Error fetching option data: {str(e)}")
|
| 133 |
+
|
| 134 |
return df
|
| 135 |
except Exception as e:
|
| 136 |
print(f"Error fetching data: {str(e)}")
|
|
|
|
| 143 |
return "Error: Mistral API key not found. Please add it to the environment variables."
|
| 144 |
|
| 145 |
# Get last 10 days of data
|
| 146 |
+
last_10_days = df.tail(10)
|
| 147 |
+
|
| 148 |
+
# Get options data if available
|
| 149 |
+
options_info = ""
|
| 150 |
+
if hasattr(df, 'attrs') and 'options_data' in df.attrs:
|
| 151 |
+
atm_strike = df.attrs['atm_strike']
|
| 152 |
+
top_strikes = df.attrs['top_strikes']
|
| 153 |
+
|
| 154 |
+
options_info = "\n\nOptions Data:\n"
|
| 155 |
+
options_info += f"ATM Strike: {atm_strike}\n\n"
|
| 156 |
+
options_info += "Top 5 Strikes by Open Interest:\n"
|
| 157 |
+
|
| 158 |
+
for strike_price, data in top_strikes:
|
| 159 |
+
ce_data = data['CE']
|
| 160 |
+
pe_data = data['PE']
|
| 161 |
+
options_info += f"\nStrike {strike_price}:\n"
|
| 162 |
+
options_info += f"Call - OI: {ce_data['OI']}, Volume: {ce_data['Volume']}, LTP: {ce_data['LTP']}\n"
|
| 163 |
+
options_info += f"Put - OI: {pe_data['OI']}, Volume: {pe_data['Volume']}, LTP: {pe_data['LTP']}\n"
|
| 164 |
|
| 165 |
# Format data for prompt
|
| 166 |
data_str = f"""This is the last 10 days data for {symbol} index:
|
| 167 |
Open High Low Close
|
| 168 |
"""
|
| 169 |
+
for _, row in last_10_days.iterrows():
|
| 170 |
data_str += f"{row['Open']}\t{row['High']}\t{row['Low']}\t{row['Close']}\n"
|
| 171 |
|
| 172 |
+
data_str += options_info
|
| 173 |
+
data_str += "\nBased on the index price action and options data, please provide:"
|
| 174 |
+
data_str += "\n1. Index price action analysis with key levels"
|
| 175 |
+
data_str += "\n2. Potential option trades with specific strikes"
|
| 176 |
+
data_str += "\n3. Entry, target, and stop loss for both index and suggested option strikes"
|
| 177 |
|
| 178 |
url = "https://api.mistral.ai/v1/chat/completions"
|
| 179 |
|
|
|
|
| 185 |
data = {
|
| 186 |
"model": "mistral-small",
|
| 187 |
"messages": [
|
| 188 |
+
{"role": "system", "content": """You are a professional options trader specializing in index options and price action analysis. When analyzing market data:
|
| 189 |
+
|
| 190 |
+
1. First analyze index price action:
|
| 191 |
+
- Key support and resistance levels
|
| 192 |
+
- Current market position
|
| 193 |
+
- Potential price targets and stop loss levels
|
| 194 |
|
| 195 |
+
2. Then analyze options data:
|
| 196 |
+
- Focus on strikes with highest open interest
|
| 197 |
+
- Compare Call vs Put open interest
|
| 198 |
+
- Look for unusual volume patterns
|
| 199 |
|
| 200 |
+
3. Provide specific trade setups:
|
| 201 |
+
- Index levels: Entry, Target, Stop Loss
|
| 202 |
+
- Option trades: Specific strikes to trade
|
| 203 |
+
- For each option trade suggested:
|
| 204 |
+
* Strike selection rationale
|
| 205 |
+
* Entry price range
|
| 206 |
+
* Target price
|
| 207 |
+
* Stop loss price
|
| 208 |
+
* Risk-reward ratio
|
| 209 |
|
| 210 |
+
Keep analysis focused on price action and option chain data. No technical indicators."""},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
{"role": "user", "content": data_str}
|
| 212 |
],
|
| 213 |
"temperature": 0.7,
|