feat: Phase 1 — IV Rank, Term Structure, Skew, Options Flow (Sprint 1.1/1.2/1.3)

Backend:
- iv_engine.py: ATM IV, term structure (30/60/90/180j), put/call skew,
  options flow (P/C OI ratio, unusual strikes, gamma bias), proxy map for futures→ETFs
- database.py: iv_history table + save_iv_snapshot, get_iv_rank_percentile, get_iv_history
- routers/options_vol.py: /api/options-vol/ endpoints (snapshot, batch, watchlist, history)
- auto_cycle.py: inject IV context string into scoring prompt (step 3.5)
- ai_analyzer.py: score_patterns_with_context accepts iv_context param
- main.py: register options_vol router

Frontend:
- pages/OptionsLab.tsx: full IV dashboard (watchlist by IVR, term structure, skew, flow, sparkline)
- pages/JournalDeBord.tsx: IvRankCell component + IV Rank column per trade
- hooks/useApi.ts: useIvSnapshot, useIvWatchlist, useIvBatch, useIvHistory, useIvForTrade

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-17 16:29:33 +02:00
parent 07c1a74704
commit 9a6b6f70b1
12 changed files with 3886 additions and 329 deletions

View File

@@ -573,3 +573,43 @@ export const useDeleteKbEntry = () => {
onSuccess: () => qc.invalidateQueries({ queryKey: ['knowledge-entries'] }),
})
}
// ── Options Volatility ────────────────────────────────────────────────────────
export const useIvSnapshot = (ticker: string) =>
useQuery({
queryKey: ['iv-snapshot', ticker],
queryFn: () => api.get(`/options-vol/snapshot/${encodeURIComponent(ticker)}`).then(r => r.data),
enabled: !!ticker,
staleTime: 60 * 60_000, // 1h — IV doesn't change that fast
})
export const useIvWatchlist = () =>
useQuery({
queryKey: ['iv-watchlist'],
queryFn: () => api.get('/options-vol/watchlist').then(r => r.data),
staleTime: 60 * 60_000,
})
export const useIvBatch = (tickers: string) =>
useQuery({
queryKey: ['iv-batch', tickers],
queryFn: () => api.get('/options-vol/batch', { params: { tickers } }).then(r => r.data),
enabled: !!tickers,
staleTime: 60 * 60_000,
})
export const useIvHistory = (ticker: string, days = 90) =>
useQuery({
queryKey: ['iv-history', ticker, days],
queryFn: () => api.get(`/options-vol/history/${encodeURIComponent(ticker)}`, { params: { days } }).then(r => r.data),
enabled: !!ticker,
staleTime: 60 * 60_000,
})
export const useIvForTrade = (underlying: string) =>
useQuery({
queryKey: ['iv-for-trade', underlying],
queryFn: () => api.get(`/options-vol/for-trade/${encodeURIComponent(underlying)}`).then(r => r.data),
enabled: !!underlying,
staleTime: 60 * 60_000,
})