feat: strategy builder

This commit is contained in:
OpenSquared
2026-07-30 13:28:03 +02:00
parent 1c4d8013c4
commit 81165581d7
8 changed files with 361 additions and 69 deletions

View File

@@ -265,7 +265,7 @@ export const useBacktestSymbols = () =>
staleTime: 60_000,
})
export type BacktestLegPreset = { option_type: 'call' | 'put'; position: 'long' | 'short'; quantity: number; strike_pct: number; expiry: 'near' | 'far' }
export type BacktestLegPreset = { option_type: 'call' | 'put' | 'stock'; position: 'long' | 'short'; quantity: number; strike_pct: number; expiry: 'near' | 'far' }
export type BacktestStrategyInfo = { key: string; label: string; n_legs: number; default_legs: BacktestLegPreset[] }
export const useBacktestStrategies = () =>
useQuery<BacktestStrategyInfo[]>({
@@ -1763,7 +1763,7 @@ export type StrategyLeg = {
expiry_date: string
days_to_expiry: number
strike: number
option_type: 'call' | 'put'
option_type: 'call' | 'put' | 'stock'
position: 'long' | 'short'
quantity: number
}
@@ -1840,6 +1840,22 @@ export const usePriceStrategy = () =>
api.post<PriceCombo>('/strategy-builder/price', body).then(r => r.data),
})
// The 28-strategy catalog (services.backtest_strategies.STRATEGIES) built from the REAL
// current chain — real strikes/expiries, ready to price or replay as-is. A strategy that
// can't be built right now (e.g. calendar/diagonal with only one real expiry available)
// is simply absent from the response.
export type StrategyPreset = { key: string; label: string; n_legs: number; legs: StrategyLeg[] }
export const usePresets = (symbol: string, horizonDays: number, enabled: boolean, dteMin?: number | null, dteMax?: number | null) =>
useQuery<StrategyPreset[]>({
queryKey: ['strategy-builder-presets', symbol, horizonDays, dteMin, dteMax],
queryFn: () => api.get('/strategy-builder/presets', {
params: { symbol, horizon_days: horizonDays, dte_min: dteMin ?? undefined, dte_max: dteMax ?? undefined },
}).then(r => r.data),
enabled: enabled && !!symbol,
staleTime: 30_000,
retry: 1,
})
export type OptimizeConstraints = {
max_legs: number
delta_threshold: number | null