feat: wavelets
This commit is contained in:
@@ -1852,6 +1852,28 @@ export const useUpdateSaxoSettings = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// Wavelet Watchlist refresh — Saxo-priced quotes + wavelet recompute, own cadence
|
||||
// (services/wavelet_scheduler.py), independent of the once-a-day auto_cycle.
|
||||
export const useWaveletRefreshSettings = () =>
|
||||
useQuery<{ enabled: boolean; refresh_minutes: number }>({
|
||||
queryKey: ['wavelet-refresh-settings'],
|
||||
queryFn: () => api.get('/wavelet/refresh-settings').then(r => r.data),
|
||||
})
|
||||
|
||||
export const useUpdateWaveletRefreshSettings = () => {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: (settings: { enabled: boolean; refresh_minutes: number }) =>
|
||||
api.put('/wavelet/refresh-settings', settings).then(r => r.data),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ['wavelet-refresh-settings'] }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useWaveletRefreshNow = () =>
|
||||
useMutation({
|
||||
mutationFn: () => api.post('/wavelet/refresh-now').then(r => r.data as { signal_rows: number }),
|
||||
})
|
||||
|
||||
export type SaxoSnapshotRow = {
|
||||
id: string; symbol: string; snapshot_date: string; spot: number | null
|
||||
expiry_date: string; strike: number; option_type: 'call' | 'put'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useSources, useUpdateSources, useUpdateApiKeys, useConfig, useAiStatus, useAnalysisConfig, useSaveAnalysisConfig, useCycleStatus, useUpdateCycleConfig, useTriggerCycle, useCycleStepCatalog, useRiskProfiles, useUpsertProfile, useDeleteProfile, useExitDefaults, useSaveExitDefaults, useOptionsGate, useSaveOptionsGate, useTechIndicatorsConfig, useSaveTechIndicatorsConfig, useInstrumentsWatchlist, useAddWatchlistInstrument, useRemoveWatchlistInstrument, useSetWatchlistSaxoOptionLink, useSetWatchlistSaxoQuoteLink, useRenameWatchlistInstrument, useSaxoStatus, useDisconnectSaxo, useSaxoWatchlist, useUpdateSaxoWatchlist, useSnapshotSaxoNow, useValidateSaxoWatchlist, useSaxoCatalog, useSaxoCatalogSummary, useRefreshSaxoCatalog, useTestSaxoQuote, useSaxoSettings, useUpdateSaxoSettings, useSnapshotAllSaxoNow, useExpandSaxoWatchlist, type CycleStepDef } from '../hooks/useApi'
|
||||
import { useSources, useUpdateSources, useUpdateApiKeys, useConfig, useAiStatus, useAnalysisConfig, useSaveAnalysisConfig, useCycleStatus, useUpdateCycleConfig, useTriggerCycle, useCycleStepCatalog, useRiskProfiles, useUpsertProfile, useDeleteProfile, useExitDefaults, useSaveExitDefaults, useOptionsGate, useSaveOptionsGate, useTechIndicatorsConfig, useSaveTechIndicatorsConfig, useInstrumentsWatchlist, useAddWatchlistInstrument, useRemoveWatchlistInstrument, useSetWatchlistSaxoOptionLink, useSetWatchlistSaxoQuoteLink, useRenameWatchlistInstrument, useSaxoStatus, useDisconnectSaxo, useSaxoWatchlist, useUpdateSaxoWatchlist, useSnapshotSaxoNow, useValidateSaxoWatchlist, useSaxoCatalog, useSaxoCatalogSummary, useRefreshSaxoCatalog, useTestSaxoQuote, useSaxoSettings, useUpdateSaxoSettings, useSnapshotAllSaxoNow, useExpandSaxoWatchlist, useWaveletRefreshSettings, useUpdateWaveletRefreshSettings, useWaveletRefreshNow, type CycleStepDef } from '../hooks/useApi'
|
||||
import { Settings, Key, Globe, CheckCircle, XCircle, AlertCircle, Save, Eye, EyeOff, Brain, SlidersHorizontal, RefreshCw, Zap, Plus, Trash2, Pencil, X, Lock, Gauge, DollarSign, TrendingUp, ShieldAlert, DatabaseBackup, Radar, Link2, Unlink, Camera, ShieldCheck, ExternalLink } from 'lucide-react'
|
||||
import clsx from 'clsx'
|
||||
import SaxoLinkPicker from '../components/SaxoLinkPicker'
|
||||
@@ -492,6 +492,9 @@ function SaxoConnectionCard() {
|
||||
const { data: settings } = useSaxoSettings()
|
||||
const updateSettings = useUpdateSaxoSettings()
|
||||
const snapshotAllNow = useSnapshotAllSaxoNow()
|
||||
const { data: waveletRefreshSettings } = useWaveletRefreshSettings()
|
||||
const updateWaveletRefreshSettings = useUpdateWaveletRefreshSettings()
|
||||
const waveletRefreshNow = useWaveletRefreshNow()
|
||||
const [input, setInput] = useState('')
|
||||
const [snapMsg, setSnapMsg] = useState('')
|
||||
const { data: catalogMatches } = useSaxoCatalog(undefined, input.length >= 2 ? input : undefined)
|
||||
@@ -649,6 +652,41 @@ function SaxoConnectionCard() {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="text-xs text-slate-500 flex items-center gap-2">
|
||||
<label className="flex items-center gap-1.5 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={waveletRefreshSettings?.enabled ?? true}
|
||||
onChange={e => updateWaveletRefreshSettings.mutate({
|
||||
enabled: e.target.checked,
|
||||
refresh_minutes: waveletRefreshSettings?.refresh_minutes ?? 15,
|
||||
})}
|
||||
/>
|
||||
Prix Watchlist (Saxo) + ondelettes recalculés toutes les
|
||||
</label>
|
||||
<input
|
||||
type="number" min={1} max={720}
|
||||
value={waveletRefreshSettings?.refresh_minutes ?? ''}
|
||||
onChange={e => updateWaveletRefreshSettings.mutate({
|
||||
enabled: waveletRefreshSettings?.enabled ?? true,
|
||||
refresh_minutes: parseFloat(e.target.value) || 15,
|
||||
})}
|
||||
className="w-14 bg-dark-800 border border-slate-700/40 rounded px-1.5 py-0.5 text-xs text-white text-center"
|
||||
/>
|
||||
<span>min — indépendant du cycle complet, tourne dès le démarrage du backend</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => waveletRefreshNow.mutate()}
|
||||
disabled={waveletRefreshNow.isPending}
|
||||
title="Refresh immédiat de toute la watchlist (prix Saxo + ondelettes), sans attendre le prochain passage"
|
||||
className="flex items-center gap-1 text-xs text-slate-400 hover:text-slate-200 border border-slate-700/50 px-2 py-1 rounded disabled:opacity-40 shrink-0"
|
||||
>
|
||||
<RefreshCw className={clsx('w-3.5 h-3.5', waveletRefreshNow.isPending && 'animate-spin')} /> Rafraîchir maintenant
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="text-[10px] text-slate-600">
|
||||
Catalogue local (Futures/FX — tickers Saxo non-évidents, ex. Or = <code>OG:xcme</code>) :{' '}
|
||||
|
||||
Reference in New Issue
Block a user