Skip to content

Commit 4e3f2f9

Browse files
committed
v0.2.0: add 0DTE, exposure history, advanced volatility endpoints; SEO-optimized README
New methods: zero_dte(), exposure_history(), adv_volatility() 36 unit tests passing. Updated README with full method reference table. Bumped version to 0.2.0.
1 parent ae9515b commit 4e3f2f9

6 files changed

Lines changed: 208 additions & 79 deletions

File tree

README.md

Lines changed: 123 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Python](https://img.shields.io/pypi/pyversions/flashalpha)](https://pypi.org/project/flashalpha/)
55
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
66

7-
**Real-time options exposure analytics for Python.** Gamma exposure (GEX), delta (DEX), vanna (VEX), charm (CHEX), key levels, Black-Scholes greeks, implied volatility, Kelly sizing, and more — from the [FlashAlpha API](https://flashalpha.com).
7+
**Python client for the FlashAlpha options analytics API.** Access real-time gamma exposure (GEX), delta exposure (DEX), vanna exposure (VEX), charm exposure (CHEX), 0DTE analytics, Black-Scholes greeks, implied volatility, volatility surfaces, dealer positioning, Kelly criterion sizing, and more — all from Python.
88

99
```bash
1010
pip install flashalpha
@@ -15,9 +15,9 @@ pip install flashalpha
1515
```python
1616
from flashalpha import FlashAlpha
1717

18-
fa = FlashAlpha("YOUR_API_KEY")
18+
fa = FlashAlpha("YOUR_API_KEY") # Get a free key at flashalpha.com
1919

20-
# Get gamma exposure for SPY
20+
# Gamma exposure by strike
2121
gex = fa.gex("SPY")
2222
print(f"Net GEX: ${gex['net_gex']:,.0f}")
2323
print(f"Gamma flip: {gex['gamma_flip']}")
@@ -26,110 +26,121 @@ for strike in gex["strikes"][:5]:
2626
print(f" {strike['strike']}: net ${strike['net_gex']:,.0f}")
2727
```
2828

29-
## What You Can Do
29+
Get your free API key at [flashalpha.com](https://flashalpha.com) — 10 requests/day, no credit card.
3030

31-
### Exposure Analytics — see where dealers are positioned
31+
## Features
3232

33-
```python
34-
# Gamma exposure by strike
35-
gex = fa.gex("SPY")
36-
gex = fa.gex("TSLA", expiration="2026-03-21", min_oi=100)
33+
### Options Exposure Analytics
3734

38-
# Delta, vanna, charm exposure
39-
dex = fa.dex("AAPL")
40-
vex = fa.vex("QQQ")
41-
chex = fa.chex("NVDA")
35+
Gamma exposure, delta exposure, vanna exposure, and charm exposure by strike. See where dealers are positioned and how they need to hedge.
4236

43-
# Key levels (gamma flip, walls, max pain)
44-
levels = fa.exposure_levels("SPY")
37+
```python
38+
gex = fa.gex("SPY") # Gamma exposure
39+
dex = fa.dex("AAPL") # Delta exposure
40+
vex = fa.vex("QQQ") # Vanna exposure
41+
chex = fa.chex("NVDA") # Charm exposure
42+
43+
levels = fa.exposure_levels("SPY") # Key levels
4544
print(f"Call wall: {levels['levels']['call_wall']}")
4645
print(f"Put wall: {levels['levels']['put_wall']}")
4746
print(f"Gamma flip: {levels['levels']['gamma_flip']}")
4847

49-
# Full exposure summary with hedging estimates
50-
summary = fa.exposure_summary("SPY") # Growth+
51-
52-
# AI narrative analysis
53-
narrative = fa.narrative("SPY") # Growth+
54-
print(narrative["narrative"]["regime"])
48+
summary = fa.exposure_summary("SPY") # Full summary (Growth+)
49+
narrative = fa.narrative("SPY") # AI narrative (Growth+)
5550
print(narrative["narrative"]["outlook"])
5651
```
5752

58-
### Market Data — live quotes and option chains
59-
60-
```python
61-
# Stock quote
62-
quote = fa.stock_quote("AAPL")
63-
print(f"AAPL: ${quote['mid']}")
64-
65-
# Option quote with greeks
66-
opt = fa.option_quote("SPY", expiry="2026-03-21", strike=660, type="C") # Growth+
67-
print(f"Delta: {opt['delta']}, IV: {opt['implied_vol']}")
53+
### 0DTE Analytics
6854

69-
# Comprehensive stock summary (price, vol, exposure, macro)
70-
summary = fa.stock_summary("SPY")
55+
Real-time zero-days-to-expiration analysis: gamma regime, expected move, pin risk scoring, dealer hedging estimates, theta decay acceleration, and per-strike breakdown.
7156

72-
# Vol surface (public — no API key needed)
73-
surface = fa.surface("SPY")
57+
```python
58+
dte = fa.zero_dte("SPY") # Growth+
59+
print(f"Pin score: {dte['pin_risk']['pin_score']}/100")
60+
print(f"Expected move: ±{dte['expected_move']['remaining_1sd_pct']:.2f}%")
61+
print(f"Theta/hr: ${dte['decay']['theta_per_hour_remaining']:,.0f}")
62+
print(f"Gamma acceleration: {dte['decay']['gamma_acceleration']}x vs 7DTE")
7463
```
7564

76-
### Pricing — Black-Scholes greeks and implied vol
65+
### Black-Scholes Greeks and Implied Volatility
66+
67+
Full BSM greeks — first order (delta, gamma, theta, vega, rho), second order (vanna, charm, vomma), and third order (speed, zomma, color, ultima).
7768

7869
```python
79-
# Full BSM greeks (first, second, third order)
8070
g = fa.greeks(spot=580, strike=580, dte=30, sigma=0.18, type="call")
8171
print(f"Delta: {g['first_order']['delta']}")
82-
print(f"Gamma: {g['first_order']['gamma']}")
8372
print(f"Vanna: {g['second_order']['vanna']}")
73+
print(f"Speed: {g['third_order']['speed']}")
74+
75+
iv = fa.iv(spot=580, strike=580, dte=30, price=12.69)
76+
print(f"IV: {iv['implied_volatility_pct']}%")
77+
```
78+
79+
### Volatility Analytics
80+
81+
Realized vol, IV-RV spreads, skew profiles, term structure, GEX by DTE, theta decay, put/call breakdowns, OI concentration, hedging scenarios, and liquidity analysis.
82+
83+
```python
84+
vol = fa.volatility("TSLA") # Growth+
85+
print(f"ATM IV: {vol['atm_iv']}%")
86+
print(f"RV 20d: {vol['realized_vol']['rv_20d']}%")
87+
print(f"VRP: {vol['iv_rv_spreads']['assessment']}")
88+
print(f"Skew 25d: {vol['skew_profiles'][0]['skew_25d']}")
89+
```
90+
91+
### Advanced Volatility (SVI, Variance Surfaces, Arbitrage Detection)
92+
93+
Raw SVI parameters per expiry, total variance surface grids, butterfly and calendar arbitrage flags, higher-order greeks surfaces (vanna, charm, volga, speed), and variance swap fair values.
94+
95+
```python
96+
adv = fa.adv_volatility("SPY") # Alpha+
97+
print(f"SVI params: {adv['svi_parameters'][0]}")
98+
print(f"Arbitrage flags: {len(adv['arbitrage_flags'])}")
99+
print(f"Var swap fair vol: {adv['variance_swap_fair_values'][0]['fair_vol']}%")
100+
```
101+
102+
### Kelly Criterion Position Sizing
84103

85-
# Implied volatility from market price
86-
result = fa.iv(spot=580, strike=580, dte=30, price=12.69)
87-
print(f"IV: {result['implied_volatility_pct']}%")
104+
Optimal position sizing using numerical integration over the full lognormal distribution — not the simplified gambling formula.
88105

89-
# Kelly criterion position sizing
90-
kelly = fa.kelly( # Growth+
106+
```python
107+
kelly = fa.kelly( # Growth+
91108
spot=580, strike=580, dte=30,
92109
sigma=0.18, premium=12.69, mu=0.12,
93110
)
94111
print(kelly["recommendation"])
112+
print(f"Half-Kelly: {kelly['sizing']['half_kelly_pct']}%")
95113
```
96114

97-
### Volatility Analytics — skew, term structure, realized vol
115+
### Market Data
98116

99117
```python
100-
vol = fa.volatility("TSLA") # Growth+
101-
print(f"ATM IV: {vol['atm_iv']}%")
102-
print(f"RV 20d: {vol['realized_vol']['rv_20d']}%")
103-
print(f"VRP assessment: {vol['iv_rv_spreads']['assessment']}")
118+
quote = fa.stock_quote("AAPL") # Live stock quote
119+
opt = fa.option_quote("SPY", expiry="2026-03-21", # Option quote (Growth+)
120+
strike=660, type="C")
121+
summary = fa.stock_summary("SPY") # Comprehensive summary
122+
surface = fa.surface("SPY") # Vol surface (public)
104123
```
105124

106-
### Historical Data — minute-by-minute from ClickHouse
125+
### Historical Data (ClickHouse)
126+
127+
Minute-by-minute stock and option quotes from ClickHouse — 3.5 billion rows across 141 tickers.
107128

108129
```python
109-
# Historical stock quotes
110130
hist = fa.historical_stock_quote("SPY", date="2026-03-05", time="10:30")
111-
112-
# Historical option quotes
113131
hist_opt = fa.historical_option_quote(
114132
"SPY", date="2026-03-05", expiry="2026-03-20", strike=580, type="C"
115133
)
116134
```
117135

118-
### Reference & Account
136+
### Reference Data and Account
119137

120138
```python
121-
# All available tickers
122-
tickers = fa.tickers()
123-
124-
# Option chain metadata (expirations + strikes)
125-
chain = fa.options("SPY")
126-
127-
# Symbols with live cached data
128-
symbols = fa.symbols()
129-
130-
# Account info and quota
131-
account = fa.account()
132-
print(f"Plan: {account['plan']}, Remaining: {account['remaining']}")
139+
tickers = fa.tickers() # All available stock tickers
140+
chain = fa.options("SPY") # Option chain metadata
141+
symbols = fa.symbols() # Symbols with live cached data
142+
account = fa.account() # Plan, usage, quota
143+
health = fa.health() # API health check (public)
133144
```
134145

135146
## Error Handling
@@ -157,18 +168,54 @@ except RateLimitError as e:
157168
print(f"Rate limited — retry after {e.retry_after}s")
158169
```
159170

160-
## Plans
161-
162-
| Plan | Daily Requests | Highlights |
163-
|------|---------------|------------|
164-
| **Free** | 50 | Stock quotes, GEX/DEX/VEX/CHEX by strike, levels, greeks, IV, tickers |
165-
| **Basic** | 250 | Everything in Free |
166-
| **Growth** | 2,500 | + Option quotes, exposure summary, narrative, volatility, Kelly sizing |
167-
| **Pro** | Unlimited | Full access |
168-
169-
**Get your API key at [flashalpha.com](https://flashalpha.com)**
171+
## API Plans
172+
173+
| Plan | Daily Requests | Access |
174+
|------|---------------|--------|
175+
| **Free** | 10 | Stock quotes, GEX/DEX/VEX/CHEX by strike, levels, BSM greeks, IV, historical quotes, tickers, options meta, surface, stock summary |
176+
| **Basic** | 250 | Everything in Free + index symbols (SPX, VIX, RUT, etc.) |
177+
| **Growth** | 2,500 | + Exposure summary, narrative, 0DTE analytics, volatility analytics, option quotes, full-chain GEX, Kelly sizing |
178+
| **Alpha** | Unlimited | + Advanced volatility (SVI, variance surfaces, arbitrage detection, greeks surfaces, variance swap) |
179+
180+
Get your API key at **[flashalpha.com](https://flashalpha.com)**
181+
182+
## All Methods
183+
184+
| Method | Endpoint | Plan |
185+
|--------|----------|------|
186+
| `fa.gex(symbol)` | Gamma exposure by strike | Free+ |
187+
| `fa.dex(symbol)` | Delta exposure by strike | Free+ |
188+
| `fa.vex(symbol)` | Vanna exposure by strike | Free+ |
189+
| `fa.chex(symbol)` | Charm exposure by strike | Free+ |
190+
| `fa.exposure_levels(symbol)` | Key levels (gamma flip, walls, max pain) | Free+ |
191+
| `fa.exposure_summary(symbol)` | Full exposure summary with hedging | Growth+ |
192+
| `fa.narrative(symbol)` | AI narrative analysis | Growth+ |
193+
| `fa.zero_dte(symbol)` | 0DTE analytics (regime, pin risk, decay) | Growth+ |
194+
| `fa.exposure_history(symbol)` | Daily exposure snapshots | Growth+ |
195+
| `fa.stock_quote(ticker)` | Live stock quote | Free+ |
196+
| `fa.option_quote(ticker)` | Option quotes with greeks | Growth+ |
197+
| `fa.stock_summary(symbol)` | Comprehensive stock summary | Public/Free+ |
198+
| `fa.surface(symbol)` | Volatility surface grid | Public |
199+
| `fa.historical_stock_quote(ticker)` | Historical stock quotes | Free+ |
200+
| `fa.historical_option_quote(ticker)` | Historical option quotes | Free+ |
201+
| `fa.greeks(...)` | BSM greeks (1st, 2nd, 3rd order) | Free+ |
202+
| `fa.iv(...)` | Implied volatility solver | Free+ |
203+
| `fa.kelly(...)` | Kelly criterion sizing | Growth+ |
204+
| `fa.volatility(symbol)` | Comprehensive volatility analytics | Growth+ |
205+
| `fa.adv_volatility(symbol)` | SVI, variance surface, arb detection | Alpha+ |
206+
| `fa.tickers()` | All available stock tickers | Free+ |
207+
| `fa.options(ticker)` | Option chain metadata | Free+ |
208+
| `fa.symbols()` | Symbols with live data | Free+ |
209+
| `fa.account()` | Account info and quota | Free+ |
210+
| `fa.health()` | Health check | Public |
170211

171212
## Links
172213

214+
- [FlashAlpha](https://flashalpha.com) — API keys, docs, pricing
173215
- [API Documentation](https://flashalpha.com/docs)
174-
- [GitHub](https://github.com/FlashAlpha-lab/flashalpha-python)
216+
- [Examples](https://github.com/FlashAlpha-lab/flashalpha-examples)
217+
- [GEX Explained](https://github.com/FlashAlpha-lab/gex-explained)
218+
219+
## License
220+
221+
MIT

pyproject.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "flashalpha"
7-
version = "0.1.0"
8-
description = "Python SDK for the FlashAlpha options analytics API — gamma exposure (GEX), delta, vanna, charm, greeks, and more."
7+
version = "0.2.0"
8+
description = "Python SDK for the FlashAlpha options analytics API — gamma exposure (GEX), delta, vanna, charm, greeks, 0DTE analytics, volatility surfaces, and more."
99
readme = "README.md"
1010
license = "MIT"
1111
requires-python = ">=3.10"
@@ -25,6 +25,15 @@ keywords = [
2525
"trading",
2626
"finance",
2727
"quantitative finance",
28+
"0dte",
29+
"zero dte",
30+
"volatility surface",
31+
"options data",
32+
"dealer positioning",
33+
"kelly criterion",
34+
"vol surface",
35+
"SVI",
36+
"variance swap",
2837
]
2938
classifiers = [
3039
"Development Status :: 3 - Alpha",

src/flashalpha/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
TierRestrictedError,
1111
)
1212

13-
__version__ = "0.1.0"
13+
__version__ = "0.2.0"
1414
__all__ = [
1515
"FlashAlpha",
1616
"FlashAlphaError",

src/flashalpha/client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,20 @@ def narrative(self, symbol: str) -> dict:
187187
"""Verbal narrative analysis of exposure. Requires Growth+."""
188188
return self._get(f"/v1/exposure/narrative/{symbol}")
189189

190+
def zero_dte(self, symbol: str, *, strike_range: float | None = None) -> dict:
191+
"""Real-time 0DTE analytics: regime, expected move, pin risk, hedging, decay. Requires Growth+."""
192+
params: dict[str, Any] = {}
193+
if strike_range is not None:
194+
params["strike_range"] = strike_range
195+
return self._get(f"/v1/exposure/zero-dte/{symbol}", params or None)
196+
197+
def exposure_history(self, symbol: str, *, days: int | None = None) -> dict:
198+
"""Daily exposure snapshots for trend analysis. Requires Growth+."""
199+
params: dict[str, Any] = {}
200+
if days is not None:
201+
params["days"] = days
202+
return self._get(f"/v1/exposure/history/{symbol}", params or None)
203+
190204
# ── Pricing & Sizing ────────────────────────────────────────────
191205

192206
def greeks(
@@ -262,6 +276,10 @@ def volatility(self, symbol: str) -> dict:
262276
"""Comprehensive volatility analysis. Requires Growth+."""
263277
return self._get(f"/v1/volatility/{symbol}")
264278

279+
def adv_volatility(self, symbol: str) -> dict:
280+
"""Advanced volatility analytics: SVI parameters, variance surface, arbitrage detection, greeks surfaces, variance swap. Requires Alpha+."""
281+
return self._get(f"/v1/adv_volatility/{symbol}")
282+
265283
# ── Reference Data ──────────────────────────────────────────────
266284

267285
def tickers(self) -> dict:

tests/test_client.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,30 @@ def test_narrative(fa):
205205
assert "regime" in result["narrative"]
206206

207207

208+
@responses.activate
209+
def test_zero_dte(fa):
210+
payload = {"symbol": "SPY", "regime": {"label": "positive_gamma"}, "pin_risk": {"pin_score": 82}, "decay": {"gamma_acceleration": 2.4}}
211+
responses.get(f"{BASE}/v1/exposure/zero-dte/SPY", json=payload)
212+
result = fa.zero_dte("SPY")
213+
assert result["pin_risk"]["pin_score"] == 82
214+
215+
216+
@responses.activate
217+
def test_zero_dte_with_strike_range(fa):
218+
payload = {"symbol": "SPY", "strikes": []}
219+
responses.get(f"{BASE}/v1/exposure/zero-dte/SPY", json=payload)
220+
fa.zero_dte("SPY", strike_range=0.05)
221+
assert "strike_range=0.05" in responses.calls[0].request.url
222+
223+
224+
@responses.activate
225+
def test_exposure_history(fa):
226+
payload = {"symbol": "SPY", "days": 7, "count": 5, "snapshots": []}
227+
responses.get(f"{BASE}/v1/exposure/history/SPY", json=payload)
228+
result = fa.exposure_history("SPY", days=7)
229+
assert result["days"] == 7
230+
231+
208232
# ── Pricing ─────────────────────────────────────────────────────────
209233

210234

@@ -243,6 +267,14 @@ def test_volatility(fa):
243267
assert result["atm_iv"] == 48.5
244268

245269

270+
@responses.activate
271+
def test_adv_volatility(fa):
272+
payload = {"symbol": "SPY", "svi_parameters": [{"expiry": "2026-04-04", "a": 0.0045}], "arbitrage_flags": []}
273+
responses.get(f"{BASE}/v1/adv_volatility/SPY", json=payload)
274+
result = fa.adv_volatility("SPY")
275+
assert result["svi_parameters"][0]["a"] == 0.0045
276+
277+
246278
# ── Reference Data ──────────────────────────────────────────────────
247279

248280

0 commit comments

Comments
 (0)