feat: option lab
This commit is contained in:
@@ -326,6 +326,31 @@ export const usePositionPayoff = (posId: string, enabled: boolean) =>
|
||||
enabled,
|
||||
})
|
||||
|
||||
// "What would have been optimal, in hindsight?" — reprices the position's real legs and
|
||||
// runs the Strategy Builder optimizer against the REAL historical Saxo chain + the REALIZED
|
||||
// spot/IV move since entry (not a guessed scenario). Expensive (full optimizer run), so
|
||||
// on-demand only — not auto-fetched, call refetch() from a button.
|
||||
export type RetrospectiveCandidate = {
|
||||
template_name: string; legs: StrategyLeg[]; score: number; return_on_capital_pct: number | null
|
||||
net_pnl: number; max_gain: number | null; max_loss: number | null; net_delta_now: number
|
||||
}
|
||||
export type RetrospectiveComparison = {
|
||||
available: boolean; reason?: string
|
||||
underlying?: string; entry_date?: string; as_of?: string; horizon_days?: number
|
||||
spot_entry?: number; spot_realized?: number; realized_spot_shock_pct?: number
|
||||
iv_entry?: number; iv_realized?: number; realized_iv_shift?: number
|
||||
actual_return_pct?: number | null
|
||||
optimal_candidates?: RetrospectiveCandidate[]
|
||||
}
|
||||
|
||||
export const useRetrospectiveOptimal = (posId: string, asOf?: string) =>
|
||||
useQuery<RetrospectiveComparison>({
|
||||
queryKey: ['portfolio-retrospective-optimal', posId, asOf],
|
||||
queryFn: () => api.get(`/portfolio/positions/${posId}/retrospective-optimal`, { params: asOf ? { as_of: asOf } : {} }).then(r => r.data),
|
||||
enabled: false,
|
||||
staleTime: 5 * 60_000,
|
||||
})
|
||||
|
||||
// Reprices every open position under a handful of named macro scenarios (Risk-Off,
|
||||
// Risk-On, inflation persistante, dollar fort, baisse des matières premières) to surface
|
||||
// when several differently-named positions are really the same underlying bet.
|
||||
@@ -1048,6 +1073,36 @@ export const useSaxoIvSnapshot = (symbol: string) =>
|
||||
staleTime: 5 * 60_000,
|
||||
})
|
||||
|
||||
// Options Lab — "was this option well priced between two dates?" Picks the strike closest
|
||||
// to the underlying's realized outcome at date_b (hindsight), reprices at both dates from
|
||||
// real Saxo history, decomposes the move into Delta/Theta/Vega + a residual.
|
||||
export type PricingCheckLeg = {
|
||||
available: boolean
|
||||
price_a?: number; price_b?: number; actual_change?: number
|
||||
iv_a?: number | null; iv_b?: number | null
|
||||
intrinsic_a?: number; time_value_a?: number; intrinsic_b?: number; time_value_b?: number
|
||||
greeks_a?: { delta: number; gamma: number; theta: number; vega: number }
|
||||
attribution?: { delta_pnl: number; theta_pnl: number; vega_pnl: number; explained: number; residual: number }
|
||||
}
|
||||
export type PricingCheckResult = {
|
||||
available: boolean; reason?: string
|
||||
ticker?: string; date_a?: string; date_b?: string; elapsed_days?: number; target_dte_used?: number
|
||||
expiry_date?: string; expired_by_date_b?: boolean
|
||||
spot_a?: number; spot_b?: number; spot_change_pct?: number; chosen_strike?: number
|
||||
iv_a?: number | null; realized_vol?: number | null; vol_risk_premium?: number | null
|
||||
legs?: { call: PricingCheckLeg; put: PricingCheckLeg }
|
||||
}
|
||||
|
||||
// targetDte omitted/undefined -> backend defaults to the expiry closest to dateB (hindsight,
|
||||
// same principle as the strike selection) — only pass it to force a different expiry.
|
||||
export const usePricingCheck = (ticker: string, dateA: string, dateB: string, targetDte: number | undefined, enabled: boolean) =>
|
||||
useQuery<PricingCheckResult>({
|
||||
queryKey: ['options-pricing-check', ticker, dateA, dateB, targetDte],
|
||||
queryFn: () => api.get('/saxo/pricing-check', { params: { ticker, date_a: dateA, date_b: dateB, target_dte: targetDte } }).then(r => r.data),
|
||||
enabled: enabled && !!ticker && !!dateA && !!dateB,
|
||||
staleTime: 5 * 60_000,
|
||||
})
|
||||
|
||||
export const useSaxoIvHistory = (symbol: string, days = 90) =>
|
||||
useQuery({
|
||||
queryKey: ['saxo-iv-history', symbol, days],
|
||||
|
||||
Reference in New Issue
Block a user