feat: dynamic market ticker watchlist (Markets page)

Add ability to add/remove custom tickers (e.g. EURCHF=X) on the
Markets & Prices page without editing config. Tickers are validated
via yfinance, persisted in market_watchlist SQLite table, merged into
the quotes feed as a 'custom' group, and shown in a dedicated tab
with per-card remove buttons.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-22 21:54:58 +02:00
parent 78c60d5254
commit c3ea0b7f8c
5 changed files with 224 additions and 19 deletions

View File

@@ -20,6 +20,34 @@ export type TickerValidation = { valid: boolean; symbol: string; name?: string;
export const validateTicker = (symbol: string): Promise<TickerValidation> =>
api.get('/market/validate', { params: { symbol } }).then(r => r.data)
export const useMarketCustomTickers = () =>
useQuery<{ ticker: string; name: string; added_at: string }[]>({
queryKey: ['market-custom-tickers'],
queryFn: () => api.get('/market/custom-tickers').then(r => r.data),
})
export const useAddMarketTicker = () => {
const qc = useQueryClient()
return useMutation({
mutationFn: (ticker: string) => api.post(`/market/custom-tickers/${encodeURIComponent(ticker)}`).then(r => r.data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['market-custom-tickers'] })
qc.invalidateQueries({ queryKey: ['quotes'] })
},
})
}
export const useRemoveMarketTicker = () => {
const qc = useQueryClient()
return useMutation({
mutationFn: (ticker: string) => api.delete(`/market/custom-tickers/${encodeURIComponent(ticker)}`).then(r => r.data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['market-custom-tickers'] })
qc.invalidateQueries({ queryKey: ['quotes'] })
},
})
}
export const useHistory = (symbol: string, period = '1y', interval = '1d') =>
useQuery<HistoricalCandle[]>({
queryKey: ['history', symbol, period, interval],