feat: strategy builder
This commit is contained in:
@@ -1677,11 +1677,14 @@ export type StrategyScenario = {
|
||||
spot_shock_pct: number
|
||||
iv_level_shift: number
|
||||
skew_tilt: number
|
||||
term_shift: number
|
||||
term_slope_shift: number
|
||||
rate_shock_bps?: number
|
||||
manual_grid?: ManualGridCell[]
|
||||
rate?: number
|
||||
n_expiries?: number
|
||||
contract_size?: number
|
||||
dte_min?: number | null
|
||||
dte_max?: number | null
|
||||
}
|
||||
|
||||
export type StrategyLeg = {
|
||||
@@ -1693,7 +1696,14 @@ export type StrategyLeg = {
|
||||
quantity: number
|
||||
}
|
||||
|
||||
export type Greeks = { delta: number; gamma: number; theta: number; vega: number }
|
||||
export type Greeks = {
|
||||
delta: number; gamma: number; theta: number; vega: number; rho: number
|
||||
vanna: number; charm: number; vomma: number; veta: number; speed: number; color: number; zomma: number
|
||||
}
|
||||
export type VannaSimulation = {
|
||||
spot_shock_pct: number; iv_shock_pts: number
|
||||
delta_before: number; delta_after: number; delta_change: number
|
||||
}
|
||||
export type PayoffPoint = { underlying: number; pnl: number }
|
||||
|
||||
export type PriceCombo = {
|
||||
@@ -1710,6 +1720,7 @@ export type PriceCombo = {
|
||||
greeks_scenario: Greeks
|
||||
net_delta_now: number
|
||||
net_delta_scenario: number
|
||||
vanna_simulation: VannaSimulation | null
|
||||
at_expiry: PayoffPoint[]
|
||||
at_scenario: PayoffPoint[]
|
||||
spot: number
|
||||
@@ -1722,12 +1733,30 @@ export type StrategyCandidate = {
|
||||
legs: StrategyLeg[]
|
||||
score: number
|
||||
objective: string
|
||||
greek_match_score?: number
|
||||
final_rank_score?: number
|
||||
} & PriceCombo
|
||||
|
||||
export const useOptionChainSlice = (symbol: string, horizonDays: number, nExpiries = 3, enabled = true) =>
|
||||
export type GreekState = 'strong_negative' | 'negative' | 'neutral' | 'positive' | 'strong_positive' | 'free'
|
||||
export type GreekTolerance = 'etroite' | 'normale' | 'large'
|
||||
export type GreekTarget = { state: GreekState; tolerance: GreekTolerance; weight: number }
|
||||
export type GreekProfile = { delta: GreekTarget; gamma: GreekTarget; theta: GreekTarget; vega: GreekTarget; rho: GreekTarget }
|
||||
|
||||
export const FREE_GREEK_TARGET: GreekTarget = { state: 'free', tolerance: 'normale', weight: 50 }
|
||||
export const DEFAULT_GREEK_PROFILE: GreekProfile = {
|
||||
delta: { ...FREE_GREEK_TARGET }, gamma: { ...FREE_GREEK_TARGET }, theta: { ...FREE_GREEK_TARGET },
|
||||
vega: { ...FREE_GREEK_TARGET }, rho: { ...FREE_GREEK_TARGET },
|
||||
}
|
||||
|
||||
export const useOptionChainSlice = (
|
||||
symbol: string, horizonDays: number, nExpiries = 3, enabled = true,
|
||||
dteMin?: number | null, dteMax?: number | null,
|
||||
) =>
|
||||
useQuery<ChainSlice>({
|
||||
queryKey: ['strategy-builder-chain', symbol, horizonDays, nExpiries],
|
||||
queryFn: () => api.get('/strategy-builder/chain', { params: { symbol, horizon_days: horizonDays, n_expiries: nExpiries } }).then(r => r.data),
|
||||
queryKey: ['strategy-builder-chain', symbol, horizonDays, nExpiries, dteMin, dteMax],
|
||||
queryFn: () => api.get('/strategy-builder/chain', {
|
||||
params: { symbol, horizon_days: horizonDays, n_expiries: nExpiries, dte_min: dteMin ?? undefined, dte_max: dteMax ?? undefined },
|
||||
}).then(r => r.data),
|
||||
enabled: enabled && !!symbol,
|
||||
staleTime: 30_000,
|
||||
retry: 1,
|
||||
@@ -1747,15 +1776,35 @@ export type OptimizeConstraints = {
|
||||
top_n?: number
|
||||
}
|
||||
|
||||
export type OptimizeResponse = { candidates: StrategyCandidate[]; warnings: string[] }
|
||||
|
||||
export const useOptimizeStrategy = () =>
|
||||
useMutation({
|
||||
mutationFn: (body: { scenario: StrategyScenario; constraints: OptimizeConstraints }) =>
|
||||
api.post<StrategyCandidate[]>('/strategy-builder/optimize', body).then(r => r.data),
|
||||
mutationFn: (body: { scenario: StrategyScenario; constraints: OptimizeConstraints; greek_profile?: GreekProfile }) =>
|
||||
api.post<OptimizeResponse>('/strategy-builder/optimize', body).then(r => r.data),
|
||||
})
|
||||
|
||||
// Mode 1 of the scenario/profile/constraints split — what Greek behavior the scenario
|
||||
// alone already implies, before the user sets any explicit target (project memory:
|
||||
// Strategy Builder Greeks plan, Phase 4).
|
||||
export type SuggestedProfile = {
|
||||
delta: GreekState; gamma: GreekState; theta: GreekState; vega: GreekState; rho: GreekState
|
||||
rationale: string[]
|
||||
reading: { spot_direction: string; spot_speed: string; iv_bucket: string }
|
||||
}
|
||||
|
||||
export const useSuggestedProfile = (scenario: StrategyScenario, enabled: boolean) =>
|
||||
useQuery<SuggestedProfile>({
|
||||
queryKey: ['strategy-suggested-profile', scenario.symbol, scenario.spot_shock_pct, scenario.iv_level_shift, scenario.horizon_days],
|
||||
queryFn: () => api.post('/strategy-builder/suggested-profile', scenario).then(r => r.data),
|
||||
enabled: enabled && !!scenario.symbol,
|
||||
staleTime: 30_000,
|
||||
})
|
||||
|
||||
export type SavedScenario = {
|
||||
id: string; symbol: string; label: string; horizon_days: number
|
||||
spot_shock_pct: number; iv_level_shift: number; skew_tilt: number; term_shift: number
|
||||
spot_shock_pct: number; iv_level_shift: number; skew_tilt: number; term_slope_shift: number
|
||||
rate_shock_bps: number; dte_min: number | null; dte_max: number | null
|
||||
manual_grid: ManualGridCell[]; created_at: string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user