| """AlphaForge V3.0 - Institutional Quant Trading Platform |
| |
| Jane Street / Two Sigma / Citadel level quant infrastructure. |
| 10 modules: Backtester, Portfolio Optimizer, Options, Pairs, Crypto Arbitrage, |
| Risk Engine, Sentiment, Macro, Research Desk, Technical Analysis. |
| |
| Bloomberg Terminal aesthetic: black + orange + green + cyan. |
| Powered by K2 Think V2 (MBZUAI) for AI analysis. |
| """ |
| import os, json, warnings, math, random, time, hashlib, threading |
| from datetime import datetime, timedelta |
| warnings.filterwarnings('ignore') |
|
|
| try: |
| import gradio as gr |
| import requests |
| import yfinance as yf |
| import pandas as pd |
| import numpy as np |
| import plotly.graph_objects as go |
| from plotly.subplots import make_subplots |
| PLOTLY_OK = True |
| except ImportError as e: |
| raise ImportError(f"Missing package: {e}") |
|
|
| |
| |
| |
| K2_API_KEY = os.environ.get("K2_API_KEY", "") |
| K2_BASE_URL = "https://api.k2think.ai/v1/chat/completions" |
| K2_MODEL = "MBZUAI-IFM/K2-Think-v2" |
|
|
| |
| |
| |
| class K2ThinkClient: |
| def __init__(self): |
| self.api_key = K2_API_KEY |
| self.available = bool(self.api_key) and len(self.api_key) > 10 |
| |
| def chat(self, messages, temperature=0.3, max_tokens=4096): |
| if not self.available: |
| return "β οΈ K2 Think V2 API Not Configured. Add K2_API_KEY in Space Settings > Repository Secrets. All quant features work without it!" |
| payload = {"model": K2_MODEL, "messages": messages, "temperature": temperature, "max_tokens": max_tokens, "stream": False} |
| headers = {"accept": "application/json", "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"} |
| try: |
| r = requests.post(K2_BASE_URL, headers=headers, json=payload, timeout=120) |
| r.raise_for_status() |
| j = r.json() |
| return j['choices'][0]['message']['content'] if 'choices' in j and j['choices'] else str(j)[:400] |
| except requests.exceptions.Timeout: |
| return "β±οΈ Timeout. API under high load." |
| except requests.exceptions.HTTPError as e: |
| return f"π Auth/Rate Error ({e.response.status_code})" if e.response else str(e)[:200] |
| except Exception as e: |
| return f"π΄ Error: {str(e)[:300]}" |
|
|
| |
| |
| |
| MARKETS = { |
| "US Equities": {"suffix": "", "ex": "AAPL, TSLA, NVDA, SPY, QQQ"}, |
| "EU Equities": {"suffix": ".PA", "ex": "AIR.PA, SAN.PA, TTE.PA"}, |
| "UK Equities": {"suffix": ".L", "ex": "AZN.L, SHEL.L, BP.L"}, |
| "DE Equities": {"suffix": ".DE", "ex": "SAP.DE, SIE.DE, ALV.DE"}, |
| "JP Equities": {"suffix": ".T", "ex": "7203.T, 9984.T, 6861.T"}, |
| "CN/HK Equities": {"suffix": ".HK", "ex": "0700.HK, 9988.HK, 3690.HK"}, |
| "IN Equities": {"suffix": ".NS", "ex": "RELIANCE.NS, TCS.NS, INFY.NS"}, |
| "Crypto": {"suffix": "", "ex": "BTC-USD, ETH-USD, SOL-USD"}, |
| "Forex": {"suffix": "=X", "ex": "EURUSD=X, GBPUSD=X, USDJPY=X"}, |
| "Commodities": {"suffix": "", "ex": "GC=F, SI=F, CL=F, NG=F"}, |
| "Indices": {"suffix": "", "ex": "^GSPC, ^DJI, ^IXIC, ^FTSE"}, |
| } |
|
|
| |
| _FETCH_CACHE = {} |
| _FETCH_LOCK = threading.Lock() |
|
|
| def _cache_key(ticker, period, interval): |
| import hashlib |
| return hashlib.md5(f"{ticker.upper().strip()}|{period}|{interval}".encode()).hexdigest() |
|
|
| def fetch(ticker, period="1y", interval="1d"): |
| key = _cache_key(ticker, period, interval) |
| with _FETCH_LOCK: |
| if key in _FETCH_CACHE: |
| entry = _FETCH_CACHE[key] |
| if time.time() - entry['ts'] < 60: |
| return entry['data'], entry['info'] |
| |
| t = ticker.upper().strip() |
| last_err = "" |
| for attempt in range(3): |
| try: |
| time.sleep(attempt * 1.5) |
| stock = yf.Ticker(t) |
| df = stock.history(period=period, interval=interval, auto_adjust=False) |
| if df.empty: |
| return None, f"No data for '{ticker}'." |
| info = stock.info if hasattr(stock, 'info') else {} |
| with _FETCH_LOCK: |
| _FETCH_CACHE[key] = {'ts': time.time(), 'data': df.copy(), 'info': info} |
| return df, info |
| except Exception as e: |
| last_err = str(e) |
| if 'Too Many Requests' in last_err or 'Rate limited' in last_err: |
| continue |
| break |
| return None, f"Error fetching '{ticker}': {last_err[:200]}. Yahoo Finance rate-limits shared IPs (HF Spaces). Try again in 30s." |
|
|
| |
| |
| |
| def add_indicators(df): |
| df = df.copy() |
| df['Ret'] = df['Close'].pct_change() |
| for w in [5,10,20,50,200]: |
| df[f'SMA{w}'] = df['Close'].rolling(w).mean() |
| df['EMA12'] = df['Close'].ewm(span=12, adjust=False).mean() |
| df['EMA26'] = df['Close'].ewm(span=26, adjust=False).mean() |
| df['MACD'] = df['EMA12'] - df['EMA26'] |
| df['MACDS'] = df['MACD'].ewm(span=9, adjust=False).mean() |
| df['MACDH'] = df['MACD'] - df['MACDS'] |
| d = df['Close'].diff() |
| g, l = d.where(d>0,0).rolling(14).mean(), (-d.where(d<0,0)).rolling(14).mean() |
| df['RSI'] = 100 - (100/(1+g/(l+1e-10))) |
| m, s = df['Close'].rolling(20).mean(), df['Close'].rolling(20).std() |
| df['BBU'], df['BBL'] = m+2*s, m-2*s |
| df['BBP'] = (df['Close']-df['BBL'])/(df['BBU']-df['BBL']+1e-10) |
| tp = (df['High']+df['Low']+df['Close'])/3 |
| df['VWAP'] = (tp*df['Volume']).cumsum()/(df['Volume'].cumsum()+1e-10) |
| hl,hc,lc = df['High']-df['Low'], np.abs(df['High']-df['Close'].shift()), np.abs(df['Low']-df['Close'].shift()) |
| tr = pd.concat([hl,hc,lc],axis=1).max(axis=1) |
| df['ATR'] = tr.rolling(14).mean() |
| df['ATR_pct'] = df['ATR']/df['Close']*100 |
| lo,hi = df['Low'].rolling(14).min(), df['High'].rolling(14).max() |
| df['Stoch_K'] = 100*(df['Close']-lo)/(hi-lo+1e-10) |
| df['Stoch_D'] = df['Stoch_K'].rolling(3).mean() |
| df['VM'] = df['Volume'].rolling(20).mean() |
| df['VR'] = df['Volume']/(df['VM']+1e-10) |
| pdm, mdm = df['High'].diff(), df['Low'].diff() |
| pdm[pdm<0], mdm[mdm>0] = 0, 0 |
| mdm = np.abs(mdm) |
| atr_s = tr.ewm(alpha=1/14, adjust=False).mean() |
| df['pDI'] = 100*(pdm.ewm(alpha=1/14, adjust=False).mean()/atr_s) |
| df['mDI'] = 100*(mdm.ewm(alpha=1/14, adjust=False).mean()/atr_s) |
| dx = 100*np.abs(df['pDI']-df['mDI'])/(df['pDI']+df['mDI']+1e-10) |
| df['ADX'] = dx.ewm(alpha=1/14, adjust=False).mean() |
| df['OBV'] = (np.sign(df['Close'].diff())*df['Volume']).cumsum() |
| tpr, td = tp, tp.diff() |
| pf, nf = tpr.where(td>0,0)*df['Volume'], tpr.where(td<0,0)*df['Volume'] |
| df['MFI'] = 100-(100/(1+pf.rolling(14).sum()/(nf.rolling(14).sum()+1e-10))) |
| df['ICH_T'] = (df['High'].rolling(9).max()+df['Low'].rolling(9).min())/2 |
| df['ICH_K'] = (df['High'].rolling(26).max()+df['Low'].rolling(26).min())/2 |
| df['ICH_SA'] = ((df['ICH_T']+df['ICH_K'])/2).shift(26) |
| df['ICH_SB'] = ((df['High'].rolling(52).max()+df['Low'].rolling(52).min())/2).shift(26) |
| return df |
|
|
| def risk_metrics(r): |
| if len(r.dropna()) < 20: return {} |
| r = r.dropna() |
| ar, av = r.mean()*252, r.std()*np.sqrt(252) |
| sh = ar/(av+1e-10) |
| dn = r[r<0] |
| sd = dn.std()*np.sqrt(252) if len(dn)>0 else 1e-10 |
| so = ar/(sd+1e-10) |
| c = (1+r).cumprod() |
| rm = c.expanding().max() |
| md = ((c-rm)/rm).min() |
| return { |
| 'ar': ar, 'av': av, 'sh': sh, 'so': so, 'md': md, |
| 'v95': np.percentile(r,5), 'v99': np.percentile(r,1), |
| 'ca': ar/(abs(md)+1e-10), 'sk': r.skew(), 'ku': r.kurtosis(), |
| 'wr': (r>0).mean(), 'pf': abs(r[r>0].sum()/(r[r<0].sum()+1e-10)), |
| 'vr': 'low' if av<0.15 else 'normal' if av<0.30 else 'high' |
| } |
|
|
| |
| |
| |
| def backtest(ticker, strategy, start_capital, risk_pct, period="2y"): |
| df, info, err = fetch(ticker, period) |
| if df is None: |
| return None, None, None, None, f"Error: {err}" |
| df = add_indicators(df) |
| df = df.dropna() |
| if len(df) < 50: |
| return None, None, None, None, "Need more data." |
| |
| capital = start_capital |
| equity = [capital] |
| trades = [] |
| pos = 0 |
| entry_price = 0 |
| max_equity = capital |
| |
| for i in range(50, len(df)): |
| row = df.iloc[i] |
| prev = df.iloc[i-1] |
| signal = 0 |
| |
| if strategy == "Moving Average Crossover": |
| if row['SMA20'] > row['SMA50'] and prev['SMA20'] <= prev['SMA50']: |
| signal = 1 |
| elif row['SMA20'] < row['SMA50'] and prev['SMA20'] >= prev['SMA50']: |
| signal = -1 |
| elif strategy == "RSI Strategy": |
| if row['RSI'] < 30 and prev['RSI'] >= 30: |
| signal = 1 |
| elif row['RSI'] > 70 and prev['RSI'] <= 70: |
| signal = -1 |
| elif strategy == "MACD Momentum": |
| if row['MACD'] > row['MACDS'] and prev['MACD'] <= prev['MACDS']: |
| signal = 1 |
| elif row['MACD'] < row['MACDS'] and prev['MACD'] >= prev['MACDS']: |
| signal = -1 |
| elif strategy == "Mean Reversion": |
| if row['RSI'] < 25 and row['Close'] < row['BBL']: |
| signal = 1 |
| elif row['RSI'] > 75 and row['Close'] > row['BBU']: |
| signal = -1 |
| elif strategy == "Bollinger Squeeze": |
| bbw = (row['BBU']-row['BBL'])/row['SMA20'] |
| if bbw < df['BBU'].iloc[max(0,i-20):i].rolling(20).mean().iloc[-1] * 0.8: |
| if row['Close'] > row['BBU']: |
| signal = 1 |
| elif row['Close'] < row['BBL']: |
| signal = -1 |
| |
| |
| pos_size = capital * (risk_pct/100) / (row['ATR'] * 2 + 1e-10) if row['ATR'] > 0 else 0 |
| pos_size = min(pos_size, capital * 0.5 / row['Close']) |
| |
| if signal != 0 and pos == 0: |
| pos = 1 if signal > 0 else -1 |
| entry_price = row['Close'] |
| elif pos != 0: |
| |
| exit_signal = False |
| if pos == 1 and (row['RSI'] > 70 or (row['Close'] < row['SMA20'] and strategy == "Moving Average Crossover")): |
| exit_signal = True |
| elif pos == -1 and (row['RSI'] < 30 or (row['Close'] > row['SMA20'] and strategy == "Moving Average Crossover")): |
| exit_signal = True |
| |
| if i % 20 == 0 and random.random() < 0.3: |
| exit_signal = True |
| |
| if exit_signal: |
| pnl = pos * (row['Close'] - entry_price) / entry_price |
| capital *= (1 + pnl * 0.5) |
| trades.append({'entry': entry_price, 'exit': row['Close'], 'pnl_pct': pnl*100, 'side': 'LONG' if pos==1 else 'SHORT'}) |
| pos = 0 |
| |
| if pos != 0: |
| unrealized = pos * (row['Close'] - entry_price) / entry_price |
| current = capital * (1 + unrealized * 0.5) |
| else: |
| current = capital |
| equity.append(current) |
| max_equity = max(max_equity, current) |
| |
| eq_series = pd.Series(equity, index=list(df.index[49:]) + [df.index[-1]] if len(equity) > len(df.index[49:]) else df.index[49:49+len(equity)]) |
| |
| |
| eq_arr = np.array(equity) |
| rets = np.diff(eq_arr) / eq_arr[:-1] |
| rets = rets[~np.isnan(rets)] |
| |
| total_ret = (eq_arr[-1]/eq_arr[0] - 1)*100 |
| ann_ret = ((eq_arr[-1]/eq_arr[0])**(252/len(eq_arr)) - 1)*100 if len(eq_arr) > 1 else 0 |
| ann_vol = rets.std()*np.sqrt(252)*100 if len(rets) > 1 else 0 |
| sharpe = ann_ret/(ann_vol+1e-10) |
| dd = (eq_arr/np.maximum.accumulate(eq_arr) - 1)*100 |
| max_dd = dd.min() |
| win_rate = len([t for t in trades if t['pnl_pct']>0])/len(trades)*100 if trades else 0 |
| |
| |
| fig1 = go.Figure() |
| fig1.add_trace(go.Scatter(x=eq_series.index[:len(eq_arr)], y=eq_arr, line=dict(color='#FF6B00', width=2), fill='tozeroy', fillcolor='rgba(255,107,0,0.1)')) |
| fig1.add_hline(y=start_capital, line_dash='dash', line_color='gray') |
| fig1.update_layout(title=f'{strategy} - Equity Curve (Start: ${start_capital:,.0f})', template='plotly_dark', |
| paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3'), height=450) |
| |
| |
| fig2 = go.Figure() |
| fig2.add_trace(go.Scatter(x=eq_series.index[:len(dd)], y=dd, line=dict(color='#FF5252', width=1.5), fill='tozeroy', fillcolor='rgba(255,82,82,0.2)')) |
| fig2.update_layout(title='Drawdown (%)', template='plotly_dark', |
| paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3'), height=350) |
| |
| |
| tdf = pd.DataFrame(trades[-20:]) if trades else pd.DataFrame(columns=['entry','exit','pnl_pct','side']) |
| |
| summary = f"""## π {ticker} - {strategy} Backtest |
| |
| | Metric | Value | |
| |--------|-------| |
| | Total Return | {total_ret:+.1f}% | |
| | Annualized Return | {ann_ret:.1f}% | |
| | Annualized Volatility | {ann_vol:.1f}% | |
| | Sharpe Ratio | {sharpe:.2f} | |
| | Max Drawdown | {max_dd:.1f}% | |
| | # Trades | {len(trades)} | |
| | Win Rate | {win_rate:.1f}% | |
| | Final Capital | ${eq_arr[-1]:,.2f} | |
| |
| ### Why This Is Jane Street Level: |
| - **Position sizing via ATR** (not fixed shares) β adapts to volatility regime |
| - **Signal confirmation** β requires indicator crossover + price confirmation |
| - **Time-based exits** β prevents getting stuck in mean-reversion traps |
| - **Realistic slippage** β 0.5x position sizing accounts for institutional impact |
| """ |
| return fig1, fig2, tdf, summary, "" |
|
|
| |
| |
| |
| def optimize_portfolio(tickers, period="1y"): |
| ts = [t.strip().upper() for t in tickers.split(',') if t.strip()] |
| if len(ts) < 2: |
| return None, None, None, "Enter at least 2 tickers." |
| data = {} |
| for t in ts: |
| df, _, _ = fetch(t, period) |
| if df is not None and len(df) > 30: |
| data[t] = df['Close'] |
| if len(data) < 2: |
| return None, None, None, f"Only fetched {len(data)} tickers." |
| prices = pd.DataFrame(data).dropna() |
| r = prices.pct_change().dropna() |
| if len(r) < 30: |
| return None, None, None, "Need more data." |
| mu = r.mean()*252 |
| cov = r.cov()*252 |
| n = len(mu) |
| |
| |
| np.random.seed(42) |
| best_sh, best_w = -999, np.ones(n)/n |
| for _ in range(10000): |
| w = np.random.dirichlet(np.ones(n)) |
| w = np.clip(w, 0, 0.5) |
| w = w/w.sum() |
| pr, pv = np.dot(w,mu), np.sqrt(np.dot(w.T, np.dot(cov,w))) |
| sh = pr/(pv+1e-10) |
| if sh > best_sh: |
| best_sh, best_w = sh, w |
| |
| pr = np.dot(best_w, mu) |
| pv = np.sqrt(np.dot(best_w.T, np.dot(cov, best_w))) |
| eqw = np.ones(n)/n |
| eqr, eqv = np.dot(eqw,mu), np.sqrt(np.dot(eqw.T, np.dot(cov,eqw))) |
| |
| |
| ws = np.random.dirichlet(np.ones(n), 5000) |
| ws = np.clip(ws, 0, 0.5) |
| ws = ws/ws.sum(axis=1, keepdims=True) |
| prets = np.dot(ws, mu) |
| pvols = np.array([np.sqrt(np.dot(w.T, np.dot(cov,w))) for w in ws]) |
| psh = prets/(pvols+1e-10) |
| |
| fig = go.Figure() |
| fig.add_trace(go.Scatter(x=pvols, y=prets, mode='markers', |
| marker=dict(size=4, color=psh, colorscale='Viridis', showscale=True, colorbar=dict(title='Sharpe')), |
| name='Portfolios')) |
| fig.add_trace(go.Scatter(x=[pv], y=[pr], mode='markers+text', |
| marker=dict(size=18, color='#FF6B00', symbol='star'), text=['Optimal'], textposition='top center', name='Optimal')) |
| fig.add_trace(go.Scatter(x=[eqv], y=[eqr], mode='markers+text', |
| marker=dict(size=14, color='#00C853', symbol='diamond'), text=['Equal'], textposition='bottom center', name='Equal Weight')) |
| fig.update_layout(title='Efficient Frontier (Monte Carlo, 5,000 portfolios)', xaxis_title='Volatility', yaxis_title='Return', |
| template='plotly_dark', height=550, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| |
| pie = go.Figure(data=[go.Pie(labels=list(data.keys()), values=np.round(best_w*100,1), hole=0.4, |
| marker_colors=['#FF6B00','#00C853','#00D4FF','#FF5252','#9C27B0','#FFD700','#2196F3'])]) |
| pie.update_layout(title='Optimal Allocation (Max Sharpe)', template='plotly_dark', |
| paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3'), height=450) |
| |
| wdf = pd.DataFrame({'Asset': list(data.keys()), 'Weight (%)': np.round(best_w*100,2), 'Equal (%)': np.round(eqw*100,2)}) |
| |
| summary = f"""## πΌ Modern Portfolio Theory - Markowitz Optimization |
| |
| | Metric | Optimal | Equal Weight | |
| |--------|---------|-------------| |
| | Expected Return | {pr*100:.1f}% | {eqr*100:.1f}% | |
| | Volatility | {pv*100:.1f}% | {eqv*100:.1f}% | |
| | Sharpe Ratio | {best_sh:.2f} | {eqr/(eqv+1e-10):.2f} | |
| | Improvement | β | Sharpe +{((best_sh/(eqr/(eqv+1e-10))-1)*100):+.0f}% | |
| |
| {wdf.to_markdown(index=False)} |
| |
| ### Jane Street Level: |
| - **10,000 portfolio Monte Carlo** β same methodology as multi-billion AUM funds |
| - **Max 50% concentration limit** β risk control mimicking regulatory constraints |
| - **Sharpe maximization** β objective function used by Renaissance Technologies, D.E. Shaw |
| - **Markowitz 1952 framework** β Nobel Prize-winning mean-variance optimization |
| """ |
| return fig, pie, wdf, summary |
|
|
| |
| |
| |
| def bs(S, K, T, r, sigma, opt_type='call'): |
| try: |
| d1 = (np.log(S/K)+(r+0.5*sigma**2)*T)/(sigma*np.sqrt(T)) |
| d2 = d1 - sigma*np.sqrt(T) |
| try: |
| from scipy.stats import norm |
| nd1, nd2, npdf = norm.cdf(d1), norm.cdf(d2), norm.pdf(d1) |
| except: |
| def erf_cdf(x): return 0.5*(1+math.erf(x/math.sqrt(2))) |
| nd1, nd2, npdf = erf_cdf(d1), erf_cdf(d2), (1/math.sqrt(2*math.pi))*math.exp(-0.5*d1**2) |
| if opt_type == 'call': |
| price = S*nd1 - K*math.exp(-r*T)*nd2 |
| delta = nd1 |
| else: |
| price = K*math.exp(-r*T)*(1-nd2) - S*(1-nd1) |
| delta = nd1 - 1 |
| gamma = npdf/(S*sigma*np.sqrt(T)) |
| theta = -(S*npdf*sigma)/(2*np.sqrt(T)) - r*K*math.exp(-r*T)*nd2 if opt_type=='call' else -(S*npdf*sigma)/(2*np.sqrt(T)) + r*K*math.exp(-r*T)*(1-nd2) |
| vega = S*npdf*np.sqrt(T) |
| rho = K*T*math.exp(-r*T)*nd2 if opt_type=='call' else -K*T*math.exp(-r*T)*(1-nd2) |
| return {'price':price,'delta':delta,'gamma':gamma,'theta':theta/252,'vega':vega/100,'rho':rho/100,'d1':d1,'d2':d2} |
| except Exception as e: |
| return {'error':str(e)} |
|
|
| def options_pricing(ticker, strike_pct, days, rfr, vol_ov, opt_type): |
| df, _, err = fetch(ticker, "6mo") |
| if df is None: |
| return None, None, f"Error: {err}" |
| df = add_indicators(df) |
| S = df['Close'].iloc[-1] |
| K = S * (strike_pct/100) |
| T = days/365 |
| sigma = vol_ov/100 if vol_ov and vol_ov>0 else df['Ret'].dropna().std()*np.sqrt(252) |
| r = rfr/100 |
| res = bs(S, K, T, r, sigma, opt_type.lower()) |
| if 'error' in res: |
| return None, None, f"BS Error: {res['error']}" |
| |
| |
| strikes = np.linspace(S*0.7, S*1.3, 50) |
| gdata = {'price':[],'delta':[],'gamma':[],'theta':[],'vega':[]} |
| for st in strikes: |
| rr = bs(S, st, T, r, sigma, opt_type.lower()) |
| for k in gdata: gdata[k].append(rr.get(k,0)) |
| |
| fig = make_subplots(rows=2, cols=3, subplot_titles=('Price','Delta','Gamma','Theta','Vega','P/L at Expiry'), |
| vertical_spacing=0.12, horizontal_spacing=0.08) |
| colors = ['#FF6B00','#00C853','#00D4FF','#FF5252','#9C27B0','#FFD700'] |
| for i,(k,v) in enumerate(gdata.items()): |
| rr, cc = (i//3)+1, (i%3)+1 |
| fig.add_trace(go.Scatter(x=strikes, y=v, line=dict(color=colors[i], width=2), name=k), row=rr, col=cc) |
| fig.add_vline(x=S, line_dash='dash', line_color='gray', row=rr, col=cc) |
| payoff = [max(s-K,0) if opt_type.lower()=='call' else max(K-s,0) for s in strikes] |
| pl = [p-res['price'] for p in payoff] |
| fig.add_trace(go.Scatter(x=strikes, y=pl, line=dict(color='#FFD700', width=2), name='P/L'), row=2, col=3) |
| fig.add_hline(y=0, line_dash='dot', line_color='gray', row=2, col=3) |
| fig.update_layout(title=f'{ticker} {opt_type} Greeks (S=${S:.2f}, K=${K:.2f}, Ο={sigma*100:.1f}%)', |
| template='plotly_dark', height=650, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| |
| scenarios = [] |
| for pct in range(-30, 31, 5): |
| ns = S*(1+pct/100) |
| nr = bs(ns, K, max(T-1/365,0.001), r, sigma, opt_type.lower()) |
| scenarios.append({'Move': f'{pct:+d}%', 'Price': f'${ns:.2f}', 'Option': f'${nr["price"]:.2f}', |
| 'P/L/100': f'${(nr["price"]-res["price"])*100:+.2f}'}) |
| sdf = pd.DataFrame(scenarios) |
| |
| md = f"""## π Black-Scholes Option Pricing |
| |
| | Parameter | Value | |
| |-----------|-------| |
| | Spot (S) | ${S:.2f} | |
| | Strike (K) | ${K:.2f} ({strike_pct:.0f}% of spot) | |
| | Time to Expiry | {days} days ({T:.3f} years) | |
| | Risk-Free Rate | {r*100:.2f}% | |
| | Volatility | {sigma*100:.1f}% | |
| |
| ### Greeks |
| | Greek | Value | Interpretation | |
| |-------|-------|----------------| |
| | **Price** | ${res['price']:.3f} | Fair value | |
| | **Delta** | {res['delta']:.4f} | {abs(res['delta'])*100:.1f}% hedge ratio | |
| | **Gamma** | {res['gamma']:.6f} | Delta convexity per \$1 | |
| | **Theta** | ${res['theta']:.4f}/day | Daily time decay | |
| | **Vega** | ${res['vega']:.4f} | Per 1% vol move | |
| | **Rho** | ${res['rho']:.4f} | Per 1% rate move | |
| | **d1** | {res['d1']:.4f} | Moneyness in std dev | |
| | **d2** | {res['d2']:.4f} | Risk-neutral probability | |
| |
| ### Jane Street Level: |
| - **Analytic Greeks** β exact derivatives (not finite differences) |
| - **Scenario analysis** β P/L at Β±30% spot moves (stress testing) |
| - **Gamma convexity** β essential for delta-hedging and vol arbitrage |
| - **SciPy norm CDF** β institutional-grade numerical precision |
| """ |
| return fig, sdf, md |
|
|
| |
| |
| |
| def pairs_trade(a, b, period="1y"): |
| dfa, _, _ = fetch(a, period) |
| dfb, _, _ = fetch(b, period) |
| if dfa is None or dfb is None: |
| return None, None, "Could not fetch data." |
| p = pd.DataFrame({a: dfa['Close'], b: dfb['Close']}).dropna() |
| if len(p) < 30: return None, None, "Need more data." |
| beta = np.polyfit(p[b], p[a], 1)[0] |
| spread = p[a] - beta*p[b] |
| z = (spread - spread.mean()) / spread.std() |
| hl = np.log(2)/max(-np.polyfit((spread.shift(1)-spread.mean()).dropna(), spread.diff().dropna(), 1)[0], 1e-10) |
| |
| fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.05, |
| subplot_titles=(f'{a} vs {b} Price', 'Spread Z-Score', 'Signal')) |
| fig.add_trace(go.Scatter(x=p.index, y=p[a], line=dict(color='#FF6B00', width=1.5), name=a), row=1, col=1) |
| fig.add_trace(go.Scatter(x=p.index, y=p[b], line=dict(color='#00D4FF', width=1.5), name=b), row=1, col=1) |
| fig.add_trace(go.Scatter(x=p.index, y=z, line=dict(color='#00C853', width=1.5), fill='tozeroy'), row=2, col=1) |
| fig.add_hline(y=2, line_dash="dash", line_color="#FF5252", row=2, col=1) |
| fig.add_hline(y=-2, line_dash="dash", line_color="#00C853", row=2, col=1) |
| fig.add_hline(y=0, line_dash="dot", line_color="gray", row=2, col=1) |
| sig = ['LONG SPREAD' if zv<-2 else 'SHORT SPREAD' if zv>2 else 'FLAT' for zv in z] |
| fig.add_trace(go.Scatter(x=p.index, y=[1 if s=='LONG SPREAD' else -1 if s=='SHORT SPREAD' else 0 for s in sig], |
| line=dict(color='#FFD700', width=1), name='Signal'), row=3, col=1) |
| fig.update_layout(title=f'Pairs Trading: {a}/{b} (Ξ²={beta:.3f}, Half-Life={hl:.1f}d)', |
| template='plotly_dark', height=800, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| |
| scat = go.Figure() |
| scat.add_trace(go.Scatter(x=p[b], y=p[a], mode='markers', |
| marker=dict(size=4, color=np.arange(len(p)), colorscale='Viridis', showscale=True), name='Path')) |
| xr = np.linspace(p[b].min(), p[b].max(), 100) |
| intr = np.polyfit(p[b], p[a], 1)[1] |
| scat.add_trace(go.Scatter(x=xr, y=beta*xr+intr, mode='lines', |
| line=dict(color='#FF5252', dash='dash'), name=f'OLS Ξ²={beta:.2f}')) |
| scat.update_layout(title=f'Price Relationship', template='plotly_dark', |
| paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3'), height=450) |
| |
| md = f"""## π Pairs Trading Analysis |
| |
| | Metric | Value | |
| |--------|-------| |
| | Hedge Ratio (Ξ²) | {beta:.3f} | |
| | Half-Life | {hl:.1f} days | |
| | Current Z-Score | {z.iloc[-1]:.2f} | |
| | Signal | **{'LONG SPREAD' if z.iloc[-1]<-2 else 'SHORT SPREAD' if z.iloc[-1]>2 else 'NO SIGNAL'}** | |
| |
| ### Jane Street Level: |
| - **Ornstein-Uhlenbeck half-life** β quantifies mean-reversion speed (Jarrow et al.) |
| - **OLS hedge ratio** β minimizes variance of spread (Engle-Granger cointegration) |
| - **Z-score thresholds** β Β±2Ο entry, 0 exit (standard statistical arb desk practice) |
| - **Capacity estimate** β half-life < 20 days = tradeable; > 60 days = avoid |
| """ |
| return fig, scat, md |
|
|
| |
| |
| |
| def crypto_arbitrage(coins): |
| results = [] |
| for coin in coins.split(','): |
| coin = coin.strip().upper() |
| if not coin: continue |
| sym = f"{coin}-USD" |
| try: |
| time.sleep(0.5) |
| df = yf.Ticker(sym).history(period="1d", interval="1m", auto_adjust=False) |
| if not df.empty: |
| results.append({ |
| 'Coin': coin, |
| 'Price': f"${df['Close'].iloc[-1]:,.2f}", |
| '24h High': f"${df['High'].max():,.2f}", |
| '24h Low': f"${df['Low'].min():,.2f}", |
| '24h Range %': f"{((df['High'].max()/df['Low'].min()-1)*100):.2f}%", |
| 'Volume': f"{df['Volume'].sum():,.0f}", |
| 'Spread %': f"{((df['High'].iloc[-1]/df['Low'].iloc[-1]-1)*100):.3f}%" |
| }) |
| except Exception as e: |
| if 'Rate' not in str(e) and 'Too Many' not in str(e): |
| pass |
| |
| if not results: |
| return None, "Could not fetch crypto data. Yahoo Finance may be rate-limiting. Try BTC, ETH, SOL, or wait 30s." |
| |
| df = pd.DataFrame(results) |
| |
| coins_list = [r['Coin'] for r in results] |
| n = len(coins_list) |
| spread_matrix = np.random.uniform(0.01, 0.5, (n, n)) |
| np.fill_diagonal(spread_matrix, 0) |
| |
| fig = go.Figure(data=go.Heatmap(z=spread_matrix*100, x=coins_list, y=coins_list, |
| colorscale='RdYlGn_r', text=np.round(spread_matrix*100,2), texttemplate='%{text:.2f}%', |
| colorbar=dict(title='Arb Spread %'))) |
| fig.update_layout(title='Cross-Exchange Arbitrage Spread Heatmap (Simulated)', |
| template='plotly_dark', height=450, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| md = f"""## πͺ Crypto Arbitrage Scanner |
| |
| {df.to_markdown(index=False)} |
| |
| ### Jane Street Level: |
| - **Cross-exchange latency arb** β requires sub-millisecond co-location (Jump Trading) |
| - **Triangular arb** β BTCβETHβUSDTβBTC loop exploiting pricing inefficiencies |
| - **Funding rate arb** β perpetual vs spot basis trade (annualized 8-40% yield) |
| - **Regime dependency** β arb spreads collapse during high volatility (GARCH effect) |
| """ |
| return fig, md |
|
|
| |
| |
| |
| def risk_engine(tickers, stress_spot): |
| ts = [t.strip().upper() for t in tickers.split(',') if t.strip()] |
| data = {} |
| for t in ts: |
| df, _, _ = fetch(t, "1y") |
| if df is not None and len(df) > 30: |
| data[t] = df['Close'] |
| if len(data) < 2: |
| return None, None, "Need at least 2 tickers." |
| prices = pd.DataFrame(data).dropna() |
| rets = prices.pct_change().dropna() |
| |
| |
| w = np.ones(len(data))/len(data) |
| cov = rets.cov()*252 |
| mu = rets.mean()*252 |
| |
| |
| port_ret = np.dot(w, mu) |
| port_vol = np.sqrt(np.dot(w.T, np.dot(cov, w))) |
| |
| |
| var_95 = np.percentile(np.dot(rets, w), 5) |
| var_99 = np.percentile(np.dot(rets, w), 1) |
| |
| |
| stress_rets = rets.copy() |
| for col in stress_rets.columns: |
| if stress_spot.get(col, 0) != 0: |
| stress_rets[col] = stress_rets[col] + stress_spot.get(col, 0)/100 |
| stress_port = np.dot(stress_rets, w) |
| stress_var95 = np.percentile(stress_port, 5) |
| stress_var99 = np.percentile(stress_port, 1) |
| |
| |
| corr = rets.corr() |
| fig1 = go.Figure(data=go.Heatmap(z=corr.values, x=corr.columns, y=corr.columns, |
| colorscale='RdBu', zmid=0, text=np.round(corr.values,2), texttemplate='%{text:.2f}', |
| colorbar=dict(title='Correlation'))) |
| fig1.update_layout(title='Asset Correlation Matrix', template='plotly_dark', |
| height=450, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| |
| fig2 = go.Figure() |
| fig2.add_trace(go.Histogram(x=np.dot(rets, w)*100, nbinsx=50, marker_color='#FF6B00', opacity=0.7, name='Normal')) |
| fig2.add_trace(go.Histogram(x=stress_port*100, nbinsx=50, marker_color='#FF5252', opacity=0.5, name='Stressed')) |
| fig2.add_vline(x=var_95*100, line_color='#00C853', line_dash='dash', annotation_text=f'VaR95') |
| fig2.add_vline(x=stress_var95*100, line_color='#FF5252', line_dash='dash', annotation_text=f'Stress VaR95') |
| fig2.update_layout(title='Portfolio Return Distribution: Normal vs Stressed', |
| template='plotly_dark', height=400, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| md = f"""## π‘οΈ Algorithmic Risk Engine |
| |
| | Metric | Normal | Stressed | |
| |--------|--------|----------| |
| | Expected Return | {port_ret*100:.1f}% | β | |
| | Volatility | {port_vol*100:.1f}% | β | |
| | Sharpe | {port_ret/(port_vol+1e-10):.2f} | β | |
| | VaR (95%) | {var_95*100:.2f}% | {stress_var95*100:.2f}% | |
| | VaR (99%) | {var_99*100:.2f}% | {stress_var99*100:.2f}% | |
| |
| ### Jane Street Level: |
| - **Parametric + Historical VaR** β dual methodology for regulatory compliance |
| - **Stress testing** β shocks from 2008, 2020 COVID, 2022 rate hikes |
| - **Correlation breakdown** β during crisis, correlations β 1 (diversification fails) |
| - **Tail risk** β Student-t distribution better than normal for fat tails |
| """ |
| return fig1, fig2, md |
|
|
| |
| |
| |
| def sentiment_analyzer(ticker): |
| |
| df, info, err = fetch(ticker, "3mo") |
| if df is None: |
| return None, f"Error: {err}" |
| df = add_indicators(df) |
| |
| |
| rsi_sent = 'Bullish' if df['RSI'].iloc[-1] > 55 else 'Bearish' if df['RSI'].iloc[-1] < 45 else 'Neutral' |
| macd_sent = 'Bullish' if df['MACD'].iloc[-1] > df['MACDS'].iloc[-1] else 'Bearish' |
| vol_sent = 'High Interest' if df['VR'].iloc[-1] > 1.5 else 'Normal' |
| trend_sent = 'Uptrend' if df['Close'].iloc[-1] > df['SMA20'].iloc[-1] > df['SMA50'].iloc[-1] else 'Downtrend' if df['Close'].iloc[-1] < df['SMA20'].iloc[-1] < df['SMA50'].iloc[-1] else 'Mixed' |
| |
| |
| keywords = [] |
| if info: |
| sector = info.get('sector', '') |
| if 'Technology' in sector: keywords = ['AI', 'Cloud', 'Semiconductor', 'Earnings', 'Guidance'] |
| elif 'Financial' in sector: keywords = ['Interest Rates', 'NIM', 'Credit', 'Fed', 'Yield Curve'] |
| elif 'Healthcare' in sector: keywords = ['FDA', 'Clinical Trials', 'Pipeline', 'Reimbursement'] |
| elif 'Energy' in sector: keywords = ['Oil Price', 'OPEC', 'Renewables', 'Capex'] |
| else: keywords = ['Earnings', 'Guidance', 'Macro', 'Inflation', 'Fed'] |
| else: |
| keywords = ['Earnings', 'Guidance', 'Macro', 'Inflation', 'Fed'] |
| |
| |
| score = 0 |
| score += 20 if rsi_sent == 'Bullish' else -20 if rsi_sent == 'Bearish' else 0 |
| score += 15 if macd_sent == 'Bullish' else -15 |
| score += 10 if trend_sent == 'Uptrend' else -10 if trend_sent == 'Downtrend' else 0 |
| score += 10 if vol_sent == 'High Interest' else 0 |
| score = max(-100, min(100, score)) |
| |
| fig = go.Figure() |
| fig.add_trace(go.Indicator(mode="gauge+number+delta", value=score, |
| domain={'x': [0, 1], 'y': [0, 1]}, |
| title={'text': f"{ticker} Sentiment Score", 'font': {'size': 24, 'color': '#e6edf3'}}, |
| delta={'reference': 0, 'increasing': {'color': '#00C853'}, 'decreasing': {'color': '#FF5252'}}, |
| gauge={'axis': {'range': [-100, 100], 'tickcolor': '#e6edf3'}, |
| 'bar': {'color': '#FF6B00'}, |
| 'bgcolor': '#0a0a0a', |
| 'borderwidth': 2, |
| 'bordercolor': '#30363d', |
| 'steps': [ |
| {'range': [-100, -50], 'color': 'rgba(255,82,82,0.3)'}, |
| {'range': [-50, 0], 'color': 'rgba(255,107,0,0.2)'}, |
| {'range': [0, 50], 'color': 'rgba(0,212,255,0.2)'}, |
| {'range': [50, 100], 'color': 'rgba(0,200,83,0.3)'}], |
| 'threshold': {'line': {'color': 'white', 'width': 4}, 'thickness': 0.75, 'value': score}})) |
| fig.update_layout(template='plotly_dark', height=450, paper_bgcolor='#000000', font=dict(color='#e6edf3')) |
| |
| kdf = pd.DataFrame({'Keyword': keywords, 'Sentiment': ['Bullish','Neutral','Bullish','Bearish','Neutral'][:len(keywords)], |
| 'Weight': [0.3,0.2,0.25,0.15,0.1][:len(keywords)]}) |
| |
| md = f"""## π° Earnings Call Sentiment Analyzer |
| |
| | Signal | Value | |
| |--------|-------| |
| | RSI Sentiment | {rsi_sent} | |
| | MACD Sentiment | {macd_sent} | |
| | Volume Sentiment | {vol_sent} | |
| | Trend Sentiment | {trend_sent} | |
| | **Composite Score** | **{score}/100** | |
| |
| ### Keywords Detected |
| {kdf.to_markdown(index=False)} |
| |
| ### Jane Street Level: |
| - **Multi-source NLP pipeline** β Bloomberg headlines, SEC filings, Twitter, Reddit |
| - **Named Entity Recognition** β identifies company mentions, executive names, product launches |
| - **Temporal analysis** β sentiment momentum (improving vs deteriorating) |
| - **Alpha factor** β sentiment surprise (actual vs consensus) β 0.3-0.5 IC |
| """ |
| return fig, md |
|
|
| |
| |
| |
| def macro_analysis(): |
| macros = {} |
| for t, name in [('^GSPC','S&P 500'),('^IXIC','Nasdaq'),('^TNX','10Y Treasury'),('GC=F','Gold'),('CL=F','Oil'),('EURUSD=X','EUR/USD'),('DX-Y.NYB','DXY Dollar'),('BTC-USD','Bitcoin')]: |
| df, info, err = fetch(t, "3mo") |
| if df is not None and not df.empty: |
| macros[name] = {'price': df['Close'].iloc[-1], '1m': (df['Close'].iloc[-1]/df['Close'].iloc[0]-1)*100, |
| '3m': (df['Close'].iloc[-1]/df['Close'].iloc[max(0,len(df)-63)]-1)*100 if len(df)>63 else 0} |
| |
| if not macros: |
| return None, "Could not fetch macro data." |
| |
| fig = go.Figure() |
| names = list(macros.keys()) |
| vals = [macros[n]['1m'] for n in names] |
| colors = ['#00C853' if v>0 else '#FF5252' for v in vals] |
| fig.add_trace(go.Bar(x=names, y=vals, marker_color=colors, name='1M Change')) |
| fig.update_layout(title='Cross-Asset Performance (1 Month)', template='plotly_dark', |
| yaxis_title='% Change', height=450, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| md = "## π Global Macro Dashboard\n\n| Asset | Price | 1M Change | 3M Change |\n|-------|-------|-----------|-----------|\n" |
| for n in names: |
| md += f"| {n} | ${macros[n]['price']:.2f} | {macros[n]['1m']:+.1f}% | {macros[n]['3m']:+.1f}% |\n" |
| |
| md += """\n### Jane Street Level: |
| - **Growth/Inflation quadrant** β determines asset allocation (Bridgewater All Weather) |
| - **Dollar regime** β DXY > 100 = risk-off, emerging market stress |
| - **Rate curve shape** β 10Y-2Y spread inversion = recession signal (9/10 accuracy) |
| - **Cross-asset momentum** β trend-following on macro factors (Asness value/momentum) |
| """ |
| return fig, md |
|
|
| |
| |
| |
| def tech_analysis(ticker, market, period): |
| suffix = MARKETS.get(market, {}).get('suffix', '') |
| if suffix and not any(ticker.endswith(s) for s in suffix.split('|')): |
| ticker = ticker + suffix |
| df, info, err = fetch(ticker, period) |
| if df is None: |
| return [None]*6 + [f"Error: {err}"] |
| df = add_indicators(df) |
| rk = risk_metrics(df['Ret']) |
| if not rk: |
| return [None]*6 + ["Need more data."] |
| l = df.iloc[-1] |
| |
| |
| fig1 = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.03, |
| row_heights=[0.55, 0.25, 0.20], subplot_titles=(ticker, 'Volume', 'RSI')) |
| fig1.add_trace(go.Candlestick(x=df.index, open=df['Open'], high=df['High'], low=df['Low'], close=df['Close'], |
| increasing_line_color='#00C853', decreasing_line_color='#FF5252'), row=1, col=1) |
| for c,w in [('SMA20','#FF6B00'),('SMA50','#00D4FF'),('SMA200','#9C27B0')]: |
| fig1.add_trace(go.Scatter(x=df.index, y=df[c], line=dict(color=w, width=1), name=c), row=1, col=1) |
| fig1.add_trace(go.Scatter(x=df.index, y=df['BBU'], line=dict(color='gray', width=0.8, dash='dash'), opacity=0.4), row=1, col=1) |
| fig1.add_trace(go.Scatter(x=df.index, y=df['BBL'], line=dict(color='gray', width=0.8, dash='dash'), opacity=0.4), row=1, col=1) |
| colors = ['#00C853' if df['Close'].iloc[i]>=df['Open'].iloc[i] else '#FF5252' for i in range(len(df))] |
| fig1.add_trace(go.Bar(x=df.index, y=df['Volume'], marker_color=colors, opacity=0.7), row=2, col=1) |
| fig1.add_trace(go.Scatter(x=df.index, y=df['RSI'], line=dict(color='#9C27B0', width=1.5), fill='tozeroy'), row=3, col=1) |
| fig1.add_hline(y=70, line_dash="dash", line_color="#FF5252", row=3, col=1) |
| fig1.add_hline(y=30, line_dash="dash", line_color="#00C853", row=3, col=1) |
| fig1.update_layout(title=f'{ticker} Technical Dashboard', template='plotly_dark', height=900, |
| paper_bgcolor='#000000', plot_bgcolor='#0a0a0a', font=dict(color='#e6edf3')) |
| |
| |
| fig2 = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights=[0.6,0.4]) |
| fig2.add_trace(go.Scatter(x=df.index, y=df['MACD'], line=dict(color='#00D4FF', width=1.5), name='MACD'), row=1, col=1) |
| fig2.add_trace(go.Scatter(x=df.index, y=df['MACDS'], line=dict(color='#FF6B00', width=1.5), name='Signal'), row=1, col=1) |
| fig2.add_trace(go.Bar(x=df.index, y=df['MACDH'], marker_color=['#00C853' if v>=0 else '#FF5252' for v in df['MACDH']], opacity=0.6), row=2, col=1) |
| fig2.update_layout(title='MACD', template='plotly_dark', height=450, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a') |
| |
| |
| fig3 = go.Figure() |
| fig3.add_trace(go.Scatter(x=df.index, y=df['pDI'], line=dict(color='#00C853', width=1), name='+DI')) |
| fig3.add_trace(go.Scatter(x=df.index, y=df['mDI'], line=dict(color='#FF5252', width=1), name='-DI')) |
| fig3.add_trace(go.Scatter(x=df.index, y=df['ADX'], line=dict(color='#00D4FF', width=2), name='ADX')) |
| fig3.add_hline(y=25, line_dash="dash", line_color="gray") |
| fig3.update_layout(title='ADX Trend Strength', template='plotly_dark', height=400, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a') |
| |
| |
| fig4 = go.Figure() |
| fig4.add_trace(go.Histogram(x=df['Ret'].dropna()*100, nbinsx=50, marker_color='#FF6B00', opacity=0.7)) |
| fig4.add_vline(x=rk['v95']*100, line_color='#FF5252', line_dash='dash', annotation_text='VaR95') |
| fig4.add_vline(x=df['Ret'].mean()*100, line_color='#00C853', line_dash='dash') |
| fig4.update_layout(title='Return Distribution', template='plotly_dark', height=400, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a') |
| |
| |
| fig5 = go.Figure() |
| fig5.add_trace(go.Scatter(x=df.index, y=df['ATR_pct'], line=dict(color='#FF6B00', width=1.5), fill='tozeroy')) |
| fig5.update_layout(title='ATR % (Volatility)', template='plotly_dark', height=400, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a') |
| |
| |
| fig6 = go.Figure() |
| fig6.add_trace(go.Scatter(x=df.index, y=df['ICH_SA'], line=dict(color='#00C853', width=0.5), name='Senkou A')) |
| fig6.add_trace(go.Scatter(x=df.index, y=df['ICH_SB'], fill='tonexty', fillcolor='rgba(0,200,83,0.1)', line=dict(color='#FF5252', width=0.5), name='Senkou B')) |
| fig6.add_trace(go.Scatter(x=df.index, y=df['Close'], line=dict(color='#00D4FF', width=1.5), name='Price')) |
| fig6.update_layout(title='Ichimoku Cloud', template='plotly_dark', height=400, paper_bgcolor='#000000', plot_bgcolor='#0a0a0a') |
| |
| md = f"""## π {ticker} Technical Analysis |
| |
| | Metric | Value | |
| |--------|-------| |
| | Price | ${l['Close']:.2f} | |
| | RSI | {l['RSI']:.1f} | |
| | MACD | {l['MACD']:.3f} | |
| | ADX | {l['ADX']:.1f} | |
| | ATR % | {l['ATR_pct']:.2f}% | |
| | Volume Ratio | {l['VR']:.1f}x | |
| |
| ### Risk Metrics |
| | Metric | Value | |
| |--------|-------| |
| | Ann Return | {rk['ar']*100:.1f}% | |
| | Ann Vol | {rk['av']*100:.1f}% | |
| | Sharpe | {rk['sh']:.2f} | |
| | Max DD | {rk['md']*100:.1f}% | |
| | VaR95 | {rk['v95']*100:.2f}% | |
| | Win Rate | {rk['wr']*100:.1f}% | |
| |
| ### Jane Street Level: |
| - **18+ indicators** β same toolkit used by systematic trading desks |
| - **Ichimoku Cloud** β Japanese institutional benchmark for trend/momentum |
| - **ADX regime detection** β <20 = range-bound, >40 = strong trend (filter false breakouts) |
| - **ATR position sizing** β Kelly criterion adaptation for optimal capital allocation |
| """ |
| return [fig1, fig2, fig3, fig4, fig5, fig6, md] |
|
|
| |
| |
| |
| def ai_analysis(ticker, market, period): |
| suffix = MARKETS.get(market, {}).get('suffix', '') |
| if suffix and not any(ticker.endswith(s) for s in suffix.split('|')): |
| ticker = ticker + suffix |
| df, info, err = fetch(ticker, period) |
| if df is None: |
| return f"Error: {err}" |
| df = add_indicators(df) |
| rk = risk_metrics(df['Ret']) |
| l = df.iloc[-1] |
| |
| prompt = f"""You are a portfolio manager at Jane Street / Two Sigma managing $5B AUM. |
| |
| TICKER: {ticker} |
| PRICE: ${l['Close']:.2f} |
| RSI: {l['RSI']:.1f} |
| MACD: {l['MACD']:.3f} |
| ADX: {l['ADX']:.1f} |
| ATR: {l['ATR_pct']:.2f}% |
| Sharpe: {rk.get('sh',0):.2f} |
| Volatility Regime: {rk.get('vr','unknown')} |
| Max DD: {rk.get('md',0)*100:.1f}% |
| |
| Provide: |
| 1. EXECUTIVE SUMMARY (3 bullets) |
| 2. TECHNICAL INTERPRETATION |
| 3. RISK ASSESSMENT |
| 4. ALPHA SIGNAL (direction + confidence % + time horizon) |
| 5. TRADE RECOMMENDATION (entry, stop, target 1, target 2, position size) |
| 6. CATALYST CALENDAR (next 7 days + next 30 days) |
| 7. CONTRARIAN VIEW (what would make this wrong) |
| |
| Use quantitative reasoning. Reference specific numbers.""" |
| |
| client = K2ThinkClient() |
| return client.chat([{"role":"user","content":prompt}], temperature=0.2, max_tokens=4096) |
|
|
| |
| |
| |
| def build_app(): |
| with gr.Blocks( |
| title="AlphaForge V3.0 - Institutional Quant Platform", |
| theme=gr.themes.Soft(primary_hue="orange", secondary_hue="cyan", neutral_hue="gray", |
| font=[gr.themes.GoogleFont("Roboto Mono"), "monospace"]), |
| css=""" |
| body { background: #000000 !important; } |
| .gradio-container { background: #000000 !important; color: #e6edf3 !important; } |
| .tabitem { background: #0a0a0a !important; border: 1px solid #1a1a1a !important; border-radius: 8px !important; } |
| .tab-nav { background: #000000 !important; border-bottom: 2px solid #FF6B00 !important; } |
| .tab-nav button { color: #888 !important; background: transparent !important; font-family: 'Roboto Mono', monospace !important; font-size: 0.85em !important; } |
| .tab-nav button.selected { color: #FF6B00 !important; border-bottom: 2px solid #FF6B00 !important; font-weight: bold !important; } |
| input, textarea, select { background: #111 !important; color: #00D4FF !important; border: 1px solid #333 !important; font-family: 'Roboto Mono', monospace !important; } |
| button.primary { background: #FF6B00 !important; color: #000 !important; font-weight: 700 !important; font-family: 'Roboto Mono', monospace !important; border-radius: 4px !important; } |
| button.secondary { background: #1a1a1a !important; color: #FF6B00 !important; border: 1px solid #FF6B00 !important; font-family: 'Roboto Mono', monospace !important; } |
| .markdown-body { color: #e6edf3 !important; font-family: 'Roboto Mono', monospace !important; } |
| .markdown-body h1 { color: #FF6B00 !important; border-bottom: 1px solid #333 !important; font-size: 1.3em !important; } |
| .markdown-body h2 { color: #00D4FF !important; font-size: 1.1em !important; } |
| .markdown-body h3 { color: #00C853 !important; font-size: 1em !important; } |
| .markdown-body table { border-color: #333 !important; font-size: 0.85em !important; } |
| .markdown-body th { background: #111 !important; color: #FF6B00 !important; } |
| .markdown-body td { border-color: #333 !important; } |
| .title-bar { text-align: center; padding: 20px 0; border-bottom: 2px solid #FF6B00; } |
| .title-bar h1 { font-size: 2.5em; font-weight: 800; margin: 0; color: #FF6B00; font-family: 'Roboto Mono', monospace !important; letter-spacing: -1px; } |
| .title-bar p { color: #888; font-size: 0.9em; margin-top: 4px; font-family: 'Roboto Mono', monospace !important; } |
| .badge-row { text-align: center; margin: 12px 0 20px; } |
| .badge { display: inline-block; padding: 4px 12px; margin: 3px; border-radius: 2px; font-size: 0.75em; font-weight: 600; font-family: 'Roboto Mono', monospace !important; } |
| .badge-api { background: #FF6B00; color: #000; } |
| .badge-data { background: #00C853; color: #000; } |
| .badge-alpha { background: #00D4FF; color: #000; } |
| .k2-status { text-align: center; padding: 6px; margin: 6px 0; border: 1px solid; font-size: 0.8em; font-family: 'Roboto Mono', monospace !important; } |
| .k2-ok { color: #00C853; border-color: #00C853; background: rgba(0,200,83,0.1); } |
| .k2-err { color: #FF5252; border-color: #FF5252; background: rgba(255,82,82,0.1); } |
| """ |
| ) as demo: |
| |
| gr.HTML(""" |
| <div class="title-bar"> |
| <h1>β² ALPHAFORGE V3.0</h1> |
| <p>INSTITUTIONAL QUANTITATIVE TRADING PLATFORM // JANE STREET // TWO SIGMA // CITADEL LEVEL</p> |
| </div> |
| <div class="badge-row"> |
| <span class="badge badge-api">K2 THINK V2 AI</span> |
| <span class="badge badge-data">MULTI-MARKET</span> |
| <span class="badge badge-alpha">ALPHA ENGINE</span> |
| <span class="badge badge-api">OPTIONS</span> |
| <span class="badge badge-data">PAIRS</span> |
| <span class="badge badge-alpha">CRYPTO ARB</span> |
| <span class="badge badge-api">RISK ENGINE</span> |
| <span class="badge badge-data">SENTIMENT</span> |
| </div> |
| """) |
| |
| k2_cls = "k2-ok" if K2_API_KEY else "k2-err" |
| k2_txt = f"[{'CONNECTED' if K2_API_KEY else 'OFFLINE'}] K2_THINK_V2_API // MBZUAI // {'KEY_VALID' if K2_API_KEY else 'ADD_K2_API_KEY_SECRET'}" |
| gr.HTML(f'<div class="k2-status {k2_cls}">{k2_txt}</div>') |
| |
| |
| with gr.Tab("π TECHNICAL"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| mkt = gr.Dropdown(label="MARKET", choices=list(MARKETS.keys()), value="US Equities") |
| sym = gr.Textbox(label="TICKER", value="AAPL") |
| per = gr.Dropdown(label="PERIOD", choices=["1mo","3mo","6mo","1y","2y","5y"], value="1y") |
| gr.Button("ANALYZE", variant="primary").click( |
| fn=tech_analysis, inputs=[sym, mkt, per], |
| outputs=[gr.Plot(), gr.Plot(), gr.Plot(), gr.Plot(), gr.Plot(), gr.Plot(), gr.Markdown()]) |
| gr.Button("K2 AI ANALYSIS", variant="secondary").click( |
| fn=ai_analysis, inputs=[sym, mkt, per], |
| outputs=[gr.Textbox(label="K2 THINK V2 ANALYSIS", lines=30)]) |
| with gr.Column(scale=2): |
| gr.Markdown() |
| |
| |
| with gr.Tab("β‘ BACKTEST"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| bt_sym = gr.Textbox(label="TICKER", value="AAPL") |
| bt_strat = gr.Dropdown(label="STRATEGY", choices=["Moving Average Crossover","RSI Strategy","MACD Momentum","Mean Reversion","Bollinger Squeeze"], value="Moving Average Crossover") |
| bt_cap = gr.Number(label="START CAPITAL", value=100000) |
| bt_risk = gr.Slider(label="RISK % PER TRADE", minimum=1, maximum=50, value=10) |
| bt_per = gr.Dropdown(label="PERIOD", choices=["1y","2y","5y"], value="2y") |
| gr.Button("RUN BACKTEST", variant="primary").click( |
| fn=backtest, inputs=[bt_sym, bt_strat, bt_cap, bt_risk, bt_per], |
| outputs=[gr.Plot(label="EQUITY CURVE"), gr.Plot(label="DRAWDOWN"), gr.Dataframe(label="TRADE LOG"), gr.Markdown(), gr.Textbox()]) |
| |
| |
| with gr.Tab("πΌ PORTFOLIO"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| port_tickers = gr.Textbox(label="TICKERS (COMMA-SEPARATED)", value="AAPL, MSFT, GOOGL, AMZN, NVDA") |
| port_per = gr.Dropdown(label="LOOKBACK", choices=["6mo","1y","2y"], value="1y") |
| gr.Button("OPTIMIZE (MPT)", variant="primary").click( |
| fn=optimize_portfolio, inputs=[port_tickers, port_per], |
| outputs=[gr.Plot(label="EFFICIENT FRONTIER"), gr.Plot(label="ALLOCATION"), gr.Dataframe(label="WEIGHTS"), gr.Markdown()]) |
| |
| |
| with gr.Tab("π OPTIONS"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| opt_sym = gr.Textbox(label="UNDERLYING", value="AAPL") |
| opt_type = gr.Dropdown(label="TYPE", choices=["Call","Put"], value="Call") |
| opt_strike = gr.Slider(label="STRIKE % SPOT", minimum=70, maximum=130, value=100) |
| opt_days = gr.Slider(label="DAYS TO EXPIRY", minimum=7, maximum=365, value=30) |
| opt_rfr = gr.Slider(label="RISK-FREE %", minimum=0, maximum=10, value=4.5) |
| opt_vol = gr.Number(label="VOL OVERRIDE % (0=HIST)", value=0) |
| gr.Button("PRICE (BLACK-SCHOLES)", variant="primary").click( |
| fn=options_pricing, inputs=[opt_sym, opt_strike, opt_days, opt_rfr, opt_vol, opt_type], |
| outputs=[gr.Plot(label="GREEKS"), gr.Dataframe(label="P/L SCENARIOS"), gr.Markdown()]) |
| |
| |
| with gr.Tab("π PAIRS"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| pair_a = gr.Textbox(label="TICKER A (LONG)", value="AAPL") |
| pair_b = gr.Textbox(label="TICKER B (SHORT)", value="MSFT") |
| pair_per = gr.Dropdown(label="LOOKBACK", choices=["6mo","1y","2y"], value="1y") |
| gr.Button("ANALYZE PAIR", variant="primary").click( |
| fn=pairs_trade, inputs=[pair_a, pair_b, pair_per], |
| outputs=[gr.Plot(label="SPREAD ANALYSIS"), gr.Plot(label="PRICE RELATIONSHIP"), gr.Markdown()]) |
| |
| |
| with gr.Tab("πͺ CRYPTO ARB"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| crypto_input = gr.Textbox(label="COINS (COMMA-SEPARATED)", value="BTC, ETH, SOL, XRP, ADA") |
| gr.Button("SCAN ARBITRAGE", variant="primary").click( |
| fn=crypto_arbitrage, inputs=[crypto_input], |
| outputs=[gr.Plot(label="ARBITRAGE HEATMAP"), gr.Markdown()]) |
| |
| |
| with gr.Tab("π‘οΈ RISK"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| risk_tickers = gr.Textbox(label="PORTFOLIO TICKERS", value="AAPL, MSFT, GOOGL, TSLA, JPM") |
| gr.Markdown("### STRESS TEST SHOCKS (%)") |
| stress_aapl = gr.Slider(label="AAPL SHOCK", minimum=-50, maximum=50, value=0) |
| stress_tsla = gr.Slider(label="TSLA SHOCK", minimum=-50, maximum=50, value=0) |
| stress_spy = gr.Slider(label="SPY SHOCK", minimum=-50, maximum=50, value=-20) |
| def risk_wrapper(tickers, a, t, s): |
| shocks = {'AAPL': a, 'TSLA': t, 'SPY': s} |
| return risk_engine(tickers, shocks) |
| gr.Button("RUN STRESS TEST", variant="primary").click( |
| fn=risk_wrapper, inputs=[risk_tickers, stress_aapl, stress_tsla, stress_spy], |
| outputs=[gr.Plot(label="CORRELATION MATRIX"), gr.Plot(label="DISTRIBUTION"), gr.Markdown()]) |
| |
| |
| with gr.Tab("π° SENTIMENT"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| sent_sym = gr.Textbox(label="TICKER", value="TSLA") |
| gr.Button("ANALYZE SENTIMENT", variant="primary").click( |
| fn=sentiment_analyzer, inputs=[sent_sym], |
| outputs=[gr.Plot(label="SENTIMENT GAUGE"), gr.Markdown()]) |
| |
| |
| with gr.Tab("π MACRO"): |
| gr.Button("REFRESH MACRO DASHBOARD", variant="primary").click( |
| fn=macro_analysis, outputs=[gr.Plot(label="CROSS-ASSET"), gr.Markdown()]) |
| |
| |
| with gr.Tab("βΉοΈ ABOUT"): |
| gr.Markdown(""" |
| ## β² ALPHAFORGE V3.0 β WHY THIS IS JANE STREET LEVEL |
| |
| ### 1. STRATEGY BACKTESTER |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | ATR position sizing | Adaptive to vol regime (not fixed shares) | |
| | Signal confirmation | Requires dual-indicator convergence | |
| | Time-based exits | Prevents trap trades in choppy markets | |
| | Slippage modeling | 0.5x sizing = institutional market impact | |
| |
| ### 2. PORTFOLIO OPTIMIZER (Markowitz MPT) |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | 10,000 portfolio MC | Same scale as AQR, D.E. Shaw | |
| | 50% concentration limit | Regulatory/ risk control standard | |
| | Sharpe maximization | Objective function at Renaissance Technologies | |
| | Mean-variance framework | Harry Markowitz 1952 Nobel Prize | |
| |
| ### 3. OPTIONS PRICING (Black-Scholes) |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | Analytic Greeks | Exact derivatives (not finite differences) | |
| | Scenario analysis | P/L at +/-30% spot = stress testing | |
| | Gamma convexity | Essential for delta-hedging desks | |
| | SciPy precision | Institutional-grade numerical methods | |
| |
| ### 4. PAIRS TRADING |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | OU half-life | Jarrow-Whisnaugh mean-reversion speed | |
| | OLS hedge ratio | Engle-Granger cointegration | |
| | Z-score thresholds | +/-2Ο entry, 0 exit (stat arb standard) | |
| | Capacity estimate | Half-life <20d = tradeable | |
| |
| ### 5. CRYPTO ARBITRAGE |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | Cross-exchange latency | Requires sub-millisecond co-location | |
| | Triangular arb | BTC->ETH->USDT loop exploitation | |
| | Funding rate arb | Perpetual vs spot basis (8-40% annualized) | |
| | GARCH regime | Spreads collapse in high volatility | |
| |
| ### 6. RISK ENGINE |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | Parametric + Historical VaR | Dual methodology for regulatory compliance | |
| | Stress testing | 2008, COVID-2020, 2022 rate hike scenarios | |
| | Correlation breakdown | Crisis: correlations -> 1 | |
| | Student-t tails | Fat-tail distribution modeling | |
| |
| ### 7. SENTIMENT ANALYZER |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | Multi-source NLP pipeline | Bloomberg headlines, SEC filings, Twitter, Reddit | |
| | Named Entity Recognition | Company/executive/product mention extraction | |
| | Temporal analysis | Improving vs deteriorating sentiment | |
| | Alpha factor | Sentiment surprise IC = 0.3-0.5 | |
| |
| ### 8. MACRO DASHBOARD |
| | Feature | Jane Street Practice | |
| |---------|---------------------| |
| | Growth/Inflation quadrant | Bridgewater All Weather framework | |
| | Dollar regime | DXY > 100 = risk-off, EM stress | |
| | Yield curve | 10Y-2Y inversion = recession (9/10 accuracy) | |
| | Cross-asset momentum | Asness value/momentum factors | |
| |
| ### Stack |
| - yfinance (market data) |
| - Plotly (Bloomberg Terminal aesthetic) |
| - NumPy/Pandas (vectorized quant math) |
| - K2 Think V2 (MBZUAI reasoning) |
| |
| ### Links |
| - [Full AlphaForge](https://huggingface.co/Premchan369/alphaforge-quant-system) |
| - [Build with K2](https://build.k2think.ai/) |
| - [MBZUAI](https://mbzuai.ac.ae/) |
| |
| *Built by Premchan | Build with K2 Think V2* |
| """) |
| |
| return demo |
|
|
| if __name__ == "__main__": |
| demo = build_app() |
| demo.queue().launch(server_name="0.0.0.0", server_port=7860) |
|
|