update dashboard

This commit is contained in:
MuslemRahimi 2024-10-24 11:56:55 +02:00
parent 3cdb2e3ebe
commit 5cfb116bf2
2 changed files with 230 additions and 2 deletions

View File

@ -223,8 +223,8 @@ async def get_recent_earnings(session):
pass pass
res_list = remove_duplicates(res_list) res_list = remove_duplicates(res_list)
#res_list.sort(key=lambda x: x['marketCap'], reverse=True) res_list.sort(key=lambda x: x['marketCap'], reverse=True)
res_list.sort(key=lambda x: (-parse_time(x['time']).timestamp(), -x['marketCap'])) #res_list.sort(key=lambda x: (-parse_time(x['time']).timestamp(), -x['marketCap']))
res_list = [{k: v for k, v in d.items() if k != 'marketCap'} for d in res_list] res_list = [{k: v for k, v in d.items() if k != 'marketCap'} for d in res_list]
return res_list[0:10] return res_list[0:10]

228
app/support.py Normal file
View File

@ -0,0 +1,228 @@
import pandas as pd
import numpy as np
import ujson
import matplotlib.pyplot as plt
from scipy.stats import norm
from datetime import datetime, date, timedelta
from benzinga import financial_data
import os
from dotenv import load_dotenv
import seaborn as sns
import sqlite3
def calculate_volatility(prices_df):
prices_df = prices_df.sort_values(by='date')
prices_df['return'] = prices_df['close'].pct_change()
returns = prices_df['return'].dropna()
return returns.std() * np.sqrt(252)
# Load API key from environment
load_dotenv()
api_key = os.getenv('BENZINGA_API_KEY')
fin = financial_data.Benzinga(api_key)
stock_con = sqlite3.connect('stocks.db')
query_template = """
SELECT date, close,change_percent
FROM "{ticker}"
WHERE date BETWEEN ? AND ?
"""
ticker = 'NVDA'
end_date = date.today()
start_date = end_date - timedelta(1)
end_date_str = end_date.strftime('%Y-%m-%d')
start_date_str = start_date.strftime('%Y-%m-%d')
query = query_template.format(ticker=ticker)
df_price = pd.read_sql_query(query, stock_con, params=('2024-01-01', end_date_str)).round(2)
df_price = df_price.rename(columns={"change_percent": "changesPercentage"})
volatility = calculate_volatility(df_price)
print(start_date, end_date)
print('volatility', volatility)
def get_data(ticker):
res_list = []
page = 0
while True:
try:
data = fin.options_activity(date_from=start_date_str, date_to=end_date_str, company_tickers=ticker, page=page, pagesize=1000)
data = ujson.loads(fin.output(data))['option_activity']
if not data:
break # Stop when no more data is returned
filtered_data = [{key: value for key, value in item.items() if key not in ['description_extended', 'updated']} for item in data]
res_list += filtered_data
except Exception as e:
print(e)
break
page += 1
return res_list
ticker_data = get_data(ticker)
ticker_data = [item for item in ticker_data if datetime.strptime(item['date_expiration'], '%Y-%m-%d') >= datetime.now()]
print(len(ticker_data))
def calculate_option_greeks(S, K, T, r, sigma, option_type='CALL'):
"""
Calculate option Greeks using Black-Scholes formula
S: Current stock price
K: Strike price
T: Time to expiration (in years)
r: Risk-free rate
sigma: Volatility
"""
if T <= 0:
return 0, 0
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == 'CALL':
delta = norm.cdf(d1)
gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))
else: # PUT
delta = -norm.cdf(-d1)
gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))
return delta, gamma
def process_options_data(df):
"""
Process options data and calculate DEX and GEX
"""
# Convert data types
df['strike_price'] = pd.to_numeric(df['strike_price'])
df['volume'] = pd.to_numeric(df['volume'])
df['underlying_price'] = pd.to_numeric(df['underlying_price'])
df['date_expiration'] = pd.to_datetime(df['date_expiration'])
df['date'] = pd.to_datetime(df['date'])
# Calculate time to expiration in years
df['T'] = (df['date_expiration'] - df['date']).dt.days / 365.0
# Parameters for calculations
risk_free_rate = 0.05 # Current approximate risk-free rate
# Calculate historical volatility (or you could use implied volatility if available)
sigma = volatility #df['underlying_price'].pct_change().std() * np.sqrt(252) if len(df) > 30 else 0.3
# Calculate Greeks for each option
greeks = df.apply(lambda row: calculate_option_greeks(
row['underlying_price'],
row['strike_price'],
row['T'],
risk_free_rate,
sigma,
row['put_call']
), axis=1)
df['delta'], df['gamma'] = zip(*greeks)
# Calculate DEX (Delta Exposure) and GEX (Gamma Exposure)
# Convert volume to float if it's not already
df['volume'] = df['volume'].astype(float)
# Get price per contract
df['price'] = pd.to_numeric(df['price'])
# Calculate position values
contract_multiplier = 100 # Standard option contract multiplier
df['position_value'] = df['price'] * df['volume'] * contract_multiplier
# Calculate exposures
df['dex'] = df['delta'] * df['volume'] * contract_multiplier
df['gex'] = df['gamma'] * df['volume'] * contract_multiplier * df['underlying_price'] * 0.01
return df
def plot_option_exposure(df, current_price):
"""
Create visualization of DEX and GEX profiles with focused y-axis
"""
plt.style.use('dark_background')
fig, ax = plt.subplots(figsize=(12, 8))
# Aggregate exposures by strike price
dex_by_strike = df.groupby('strike_price')['dex'].sum().reset_index()
gex_by_strike = df.groupby('strike_price')['gex'].sum().reset_index()
# Filter out strikes with no significant exposure
significant_exposure = abs(dex_by_strike['dex']) > abs(dex_by_strike['dex']).max() * 0.01
min_strike = dex_by_strike[significant_exposure]['strike_price'].min()
max_strike = dex_by_strike[significant_exposure]['strike_price'].max()
# Add some padding to the range
strike_padding = (max_strike - min_strike) * 0.1
y_min = max(min_strike - strike_padding, dex_by_strike['strike_price'].min())
y_max = min(max_strike + strike_padding, dex_by_strike['strike_price'].max())
# Plot DEX bars
positive_dex = dex_by_strike[dex_by_strike['dex'] > 0]
negative_dex = dex_by_strike[dex_by_strike['dex'] <= 0]
ax.barh(positive_dex['strike_price'], positive_dex['dex'],
color='green', alpha=0.7, label='Positive DEX')
ax.barh(negative_dex['strike_price'], negative_dex['dex'],
color='#964B00', alpha=0.7, label='Negative DEX')
# Plot GEX profile
ax.plot(gex_by_strike['gex'], gex_by_strike['strike_price'],
color='yellow', label='GEX Profile', linewidth=2)
# Calculate and plot support/resistance levels
significant_gex = gex_by_strike[abs(gex_by_strike['gex']) > abs(gex_by_strike['gex']).mean()]
resistance_level = significant_gex[significant_gex['strike_price'] > current_price]['strike_price'].min()
support_level = significant_gex[significant_gex['strike_price'] < current_price]['strike_price'].max()
# Add reference lines
if pd.notna(resistance_level):
ax.axhline(y=resistance_level, color='red', linestyle='--', alpha=0.5,
label=f'Call Resistance: {resistance_level:.1f}')
if pd.notna(support_level):
ax.axhline(y=support_level, color='green', linestyle='--', alpha=0.5,
label=f'Put Support: {support_level:.1f}')
ax.axhline(y=current_price, color='white', linestyle='--', alpha=0.5,
label=f'Spot Price: {current_price:.1f}')
# Calculate and plot HVL
hvl = dex_by_strike['strike_price'][abs(dex_by_strike['dex']).idxmin()]
ax.axhline(y=hvl, color='gray', linestyle='--', alpha=0.5,
label=f'HVL: {hvl:.1f}')
# Set y-axis limits to focus on relevant region
ax.set_ylim(y_min, y_max)
# Customize the plot
ax.set_title(f'Net DEX All Expirations for {df["ticker"].iloc[0]}\nTimestamp: {df["date"].iloc[0]}', pad=20)
ax.set_xlabel('Exposure (Contract-Adjusted)')
ax.set_ylabel('Strike Price')
ax.grid(True, alpha=0.2)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# Format axis
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1e6:.1f}B' if abs(x) >= 1e6 else f'{x/1e3:.1f}M'))
plt.tight_layout()
return fig
# Use the functions with your data
df = pd.DataFrame(ticker_data)
processed_df = process_options_data(df)
current_price = float(df['underlying_price'].iloc[0])
fig = plot_option_exposure(processed_df, current_price)
plt.show()
# Print analysis
print("\nKey Levels Analysis:")
dex_by_strike = processed_df.groupby('strike_price')['dex'].sum()
gex_by_strike = processed_df.groupby('strike_price')['gex'].sum()
print(f"Largest DEX Positive: Strike ${dex_by_strike.idxmax():.2f} (${dex_by_strike.max()/1e6:.2f}M)")
print(f"Largest DEX Negative: Strike ${dex_by_strike.idxmin():.2f} (${dex_by_strike.min()/1e6:.2f}M)")
print(f"Largest GEX: Strike ${gex_by_strike.idxmax():.2f} (${gex_by_strike.max()/1e6:.2f}M)")
print(f"Net DEX: ${dex_by_strike.sum()/1e6:.2f}M")
print(f"Net GEX: ${gex_by_strike.sum()/1e6:.2f}M")