From c4b45be757b972e6209f3b3f0ecbdcb7865f2123 Mon Sep 17 00:00:00 2001
From: "2569718930@qq.com" <2569718930@qq.com>
Date: Wed, 15 Apr 2026 16:30:13 +0800
Subject: [PATCH] Remove Polymarket price integration from dashboard
---
.../dashboard/FutureForecastModal.tsx | 138 +++---------------
frontend/hooks/useDashboardStore.tsx | 90 +-----------
frontend/lib/dashboard-client.ts | 60 --------
frontend/lib/dashboard-types.ts | 1 +
web/routes.py | 17 +--
5 files changed, 26 insertions(+), 280 deletions(-)
diff --git a/frontend/components/dashboard/FutureForecastModal.tsx b/frontend/components/dashboard/FutureForecastModal.tsx
index 2e5cd246..d9b06173 100644
--- a/frontend/components/dashboard/FutureForecastModal.tsx
+++ b/frontend/components/dashboard/FutureForecastModal.tsx
@@ -69,13 +69,6 @@ function formatMarketPercent(value?: number | null) {
return `${(normalized * 100).toFixed(1)}%`;
}
-function formatSignedPercent(value?: number | null) {
- const numeric = Number(value);
- if (!Number.isFinite(numeric)) return "--";
- const sign = numeric > 0 ? "+" : "";
- return `${sign}${numeric.toFixed(1)}%`;
-}
-
function formatBucketLabel(
bucket?: {
label?: string | null;
@@ -622,7 +615,6 @@ export function FutureForecastModal() {
const store = useDashboardStore();
const { locale, t } = useI18n();
const detail = store.selectedDetail;
- const marketScan = store.selectedMarketScan;
const dateStr = store.futureModalDate;
const isPro = store.proAccess.subscriptionActive;
const isProLoading = store.proAccess.loading;
@@ -667,8 +659,7 @@ export function FutureForecastModal() {
const detailDepth = detail.detail_depth || "full";
const isFullDetailReady = detailDepth === "full";
const isStructureSyncing = store.loadingState.futureDeep || !isFullDetailReady;
- const isMarketSyncing = store.loadingState.marketScan;
- const isAnyLayerSyncing = isStructureSyncing || isMarketSyncing;
+ const isAnyLayerSyncing = isStructureSyncing;
const view = getFutureModalView(detail, dateStr, locale);
const scorePosition = `${50 + view.front.score / 2}%`;
const barStyle = {
@@ -713,7 +704,7 @@ export function FutureForecastModal() {
const boundaryRiskView = useMemo(() => {
if (!showDeferredTodaySections) return null;
if (!isToday || !paceView) return null;
- const selectedBucket = marketScan?.temperature_bucket || null;
+ const selectedBucket = topProbabilityBucket || null;
const bounds = parseBucketBoundaries(selectedBucket);
if (!bounds) return null;
const projected =
@@ -756,7 +747,7 @@ export function FutureForecastModal() {
tone,
value: `${nearest.gap.toFixed(1)}${detail.temp_symbol}`,
};
- }, [detail.deb?.prediction, detail.temp_symbol, isToday, locale, marketScan?.temperature_bucket, paceView, showDeferredTodaySections]);
+ }, [detail.deb?.prediction, detail.temp_symbol, isToday, locale, paceView, showDeferredTodaySections, topProbabilityBucket]);
const peakWindowStateView = useMemo(() => {
if (!showDeferredTodaySections) return null;
if (!isToday || !paceView) return null;
@@ -850,27 +841,7 @@ export function FutureForecastModal() {
String(detail.current?.station_name || "").trim() ||
String(detail.risk?.airport || "").trim() ||
noaaStationCode;
- const topBucket = Array.isArray(marketScan?.top_buckets)
- ? [...marketScan.top_buckets]
- .map((item) => ({
- ...item,
- probability: normalizeMarketValue(item?.probability),
- }))
- .filter(
- (
- item,
- ): item is {
- label?: string | null;
- bucket?: string | null;
- range?: string | null;
- value?: number | null;
- temp?: number | null;
- probability: number;
- } => item.probability != null,
- )
- .sort((a, b) => b.probability - a.probability)[0]
- : null;
- const hottestBucketLabel = formatBucketLabel(topBucket);
+ const hottestBucketLabel = formatBucketLabel(topProbabilityBucket);
const probabilitySummary = (() => {
if (!topProbabilityBucket) {
return locale === "en-US"
@@ -904,17 +875,10 @@ export function FutureForecastModal() {
})();
const upperAirSignal = detail.vertical_profile_signal || {};
const tafSignal = detail.taf?.signal || {};
- const topBucketProbability = normalizeMarketValue(topBucket?.probability);
- const numericEdge = Number(marketScan?.edge_percent);
- const hottestMatchesSettlement =
- hottestBucketLabel !== "--" &&
- formatBucketLabel(marketScan?.temperature_bucket) !== "--" &&
- hottestBucketLabel === formatBucketLabel(marketScan?.temperature_bucket);
- const marketAwareUpperAirCue = useMemo(() => {
+ const upperAirCue = useMemo(() => {
if (!showDeferredTodaySections) return null;
if (!isToday || (!upperAirSignal.source && !tafSignal.available)) return null;
- const crowded = hottestMatchesSettlement && (topBucketProbability || 0) >= 0.3;
const setup = String(upperAirSignal.heating_setup || "neutral").toLowerCase();
const tafSuppression = String(
tafSignal.suppression_level || "low",
@@ -922,9 +886,6 @@ export function FutureForecastModal() {
const tafDisruption = String(
tafSignal.disruption_level || "low",
).toLowerCase();
- const signalLabel = String(marketScan?.signal_label || "").toUpperCase();
- const edgeAbs = Number.isFinite(numericEdge) ? Math.abs(numericEdge) : 0;
- const strongEdge = edgeAbs >= 8;
const reasons: string[] = [];
let score = 0;
@@ -976,37 +937,12 @@ export function FutureForecastModal() {
);
}
- if (strongEdge && signalLabel === "BUY YES") {
- score += 1;
- reasons.push(
- locale === "en-US"
- ? `market edge still leans hotter (${formatSignedPercent(numericEdge)})`
- : `市场 edge 仍偏向更热一侧(${formatSignedPercent(numericEdge)})`,
- );
- } else if (strongEdge && signalLabel === "BUY NO") {
- score -= 1;
- reasons.push(
- locale === "en-US"
- ? `market edge still leans cooler (${formatSignedPercent(numericEdge)})`
- : `市场 edge 仍偏向更冷一侧(${formatSignedPercent(numericEdge)})`,
- );
- }
-
- if (crowded && score > 0) {
- score -= 0.5;
- reasons.push(
- locale === "en-US"
- ? "the target bucket is already getting crowded"
- : "目标区间已经开始变拥挤",
- );
- }
-
if (score >= 1.5) {
return {
summary:
locale === "en-US"
- ? "The combined upper-air, TAF, and market read still leans warmer. Do not fade lower buckets too early."
- : "高空、TAF 和市场三层信号合并后仍偏暖侧,不宜过早做更低温区间。",
+ ? "The combined upper-air and TAF read still leans warmer. Do not fade lower buckets too early."
+ : "高空和 TAF 两层信号合并后仍偏暖侧,不宜过早做更低温区间。",
note:
locale === "en-US"
? `${reasons.slice(0, 2).join("; ")}.`
@@ -1020,8 +956,8 @@ export function FutureForecastModal() {
return {
summary:
locale === "en-US"
- ? "The combined upper-air, TAF, and market read leans more defensive. Be more careful chasing higher buckets."
- : "高空、TAF 和市场三层信号合并后更偏防守,追更高温区间要更谨慎。",
+ ? "The combined upper-air and TAF read leans more defensive. Be more careful chasing higher buckets."
+ : "高空和 TAF 两层信号合并后更偏防守,追更高温区间要更谨慎。",
note:
locale === "en-US"
? `${reasons.slice(0, 2).join("; ")}.`
@@ -1034,8 +970,8 @@ export function FutureForecastModal() {
return {
summary:
locale === "en-US"
- ? "The combined upper-air, TAF, and market read is mixed. Let surface structure and price action decide before taking a side."
- : "高空、TAF 和市场三层信号目前偏混合,先看近地面结构和盘口变化,不急着站边。",
+ ? "The combined upper-air and TAF read is mixed. Let surface structure decide before taking a side."
+ : "高空和 TAF 两层信号目前偏混合,先看近地面结构变化,不急着站边。",
note:
locale === "en-US"
? `${reasons.slice(0, 2).join("; ") || "No clean edge from the upper-air layer alone"}.`
@@ -1047,12 +983,8 @@ export function FutureForecastModal() {
tafSignal.available,
tafSignal.disruption_level,
tafSignal.suppression_level,
- marketScan?.signal_label,
- hottestMatchesSettlement,
isToday,
locale,
- numericEdge,
- topBucketProbability,
upperAirSignal.heating_setup,
upperAirSignal.source,
showDeferredTodaySections,
@@ -1081,18 +1013,18 @@ export function FutureForecastModal() {
};
})();
const displayedUpperAirSummary = showDeferredTodaySections
- ? marketAwareUpperAirCue?.summary || view.front.upperAirSummary
+ ? upperAirCue?.summary || view.front.upperAirSummary
: "";
const displayedUpperAirMetrics = showDeferredTodaySections
? (view.front.upperAirMetrics || []).map((metric, index) =>
index === 0 &&
(metric.label === "Trade cue" || metric.label === "交易动作") &&
- marketAwareUpperAirCue
+ upperAirCue
? {
...metric,
- note: marketAwareUpperAirCue.note,
- tone: marketAwareUpperAirCue.tone,
- value: marketAwareUpperAirCue.value,
+ note: upperAirCue.note,
+ tone: upperAirCue.tone,
+ value: upperAirCue.value,
}
: metric,
)
@@ -1162,23 +1094,15 @@ export function FutureForecastModal() {
},
{
key: "market",
- state: isMarketSyncing ? "syncing" : "ready",
+ state: "ready",
label:
locale === "en-US"
- ? isMarketSyncing
- ? "Syncing market ladder"
- : "Market ladder ready"
- : isMarketSyncing
- ? "市场挂单同步中"
- : "市场挂单已加载",
+ ? "Probability layer ready"
+ : "概率层已加载",
note:
locale === "en-US"
- ? isMarketSyncing
- ? "Polymarket buckets and edge are updating in the background."
- : "Probability buckets and edge are in sync."
- : isMarketSyncing
- ? "Polymarket 概率桶和 edge 正在后台更新。"
- : "概率桶和 edge 已同步完成。",
+ ? "Probability buckets are derived from the local model stack."
+ : "概率桶当前由本地模型栈推导。",
},
{
key: "structure",
@@ -1584,28 +1508,10 @@ export function FutureForecastModal() {
{probabilitySummary}
- {/* Loading Overlay */}
- {store.loadingState.marketScan && (
-
-
- {locale === "en-US"
- ? "Crunching Polymarket Edges..."
- : "正在同步市场挂单..."}
-
- )}
@@ -1841,7 +1747,6 @@ export function FutureForecastModal() {
detail={detail}
targetDate={dateStr}
hideTitle
- marketScan={marketScan}
/>
@@ -1861,3 +1766,4 @@ export function FutureForecastModal() {
);
}
+
diff --git a/frontend/hooks/useDashboardStore.tsx b/frontend/hooks/useDashboardStore.tsx
index ee889bea..55242a95 100644
--- a/frontend/hooks/useDashboardStore.tsx
+++ b/frontend/hooks/useDashboardStore.tsx
@@ -24,7 +24,6 @@ import {
HistoryPayloadMeta,
HistoryState,
LoadingState,
- MarketScan,
ProAccessState,
} from "@/lib/dashboard-types";
@@ -46,12 +45,10 @@ interface DashboardStoreValue extends DashboardState {
refreshAll: () => Promise;
refreshProAccess: () => Promise;
refreshSelectedCity: () => Promise;
- selectedMarketScan: MarketScan | null;
selectedDetail: CityDetail | null;
selectCity: (cityName: string) => Promise;
setMapInteractionActive: (active: boolean) => void;
setForecastDate: (dateStr: string | null) => void;
- marketScanByCityName: Record;
}
const DashboardStoreContext = createContext(null);
@@ -94,11 +91,6 @@ function getInitialProAccessState(): ProAccessState {
};
}
-function getMarketScanCacheKey(cityName: string, targetDate?: string | null) {
- const normalizedDate = String(targetDate || "").trim() || "local";
- return `${cityName}::${normalizedDate}`;
-}
-
const SELECTED_CITY_STORAGE_KEY = "polyWeather_selected_city_v1";
const BACKGROUND_SUMMARY_REFRESH_MS = 30_000;
type CityDetailDepth = "panel" | "market" | "nearby" | "full";
@@ -291,9 +283,6 @@ export function DashboardStoreProvider({
const [cityDetailMetaByName, setCityDetailMetaByName] = useState<
Record
>({});
- const [marketScanByCityName, setMarketScanByCityName] = useState<
- Record
- >({});
const [selectedCity, setSelectedCity] = useState(null);
const [isPanelOpen, setIsPanelOpen] = useState(false);
const [selectedForecastDate, setSelectedForecastDate] = useState<
@@ -325,19 +314,6 @@ export function DashboardStoreProvider({
selectedCity && proAccess.subscriptionActive
? cityDetailsByName[selectedCity] || null
: null;
- const selectedMarketDate =
- futureModalDate ||
- selectedForecastDate ||
- selectedDetail?.local_date ||
- null;
- const selectedMarketScanKey = selectedCity
- ? getMarketScanCacheKey(selectedCity, selectedMarketDate)
- : null;
- const selectedMarketScan =
- selectedCity && proAccess.subscriptionActive
- ? marketScanByCityName[selectedMarketScanKey || ""] || null
- : null;
-
useEffect(() => {
if (proAccess.loading) return;
if (!proAccess.authenticated || !proAccess.subscriptionActive) {
@@ -402,7 +378,6 @@ export function DashboardStoreProvider({
dashboardClient.clearCityDetailCache();
setCityDetailsByName({});
setCityDetailMetaByName({});
- setMarketScanByCityName({});
}, [proAccess]);
const scheduleBackgroundDetailRefresh = (
@@ -578,32 +553,6 @@ export function DashboardStoreProvider({
selectedCity,
]);
- const ensureCityMarketScan = async (
- cityName: string,
- force = false,
- marketSlug?: string | null,
- targetDate?: string | null,
- ) => {
- const cacheKey = getMarketScanCacheKey(cityName, targetDate);
- const cached = marketScanByCityName[cacheKey];
- if (!force && cached && !marketSlug) {
- return cached;
- }
-
- const latestScan = await dashboardClient.getCityMarketScan(cityName, {
- force,
- marketSlug,
- targetDate,
- });
- if (latestScan) {
- setMarketScanByCityName((current) => ({
- ...current,
- [cacheKey]: latestScan,
- }));
- }
- return latestScan;
- };
-
const loadCities = async () => {
setLoadingState((current) => ({ ...current, cities: true }));
try {
@@ -1055,8 +1004,6 @@ export function DashboardStoreProvider({
);
setFutureModalDate(dateStr);
- const cacheKey = getMarketScanCacheKey(selectedCity, dateStr);
- setLoadingState((current) => ({ ...current, marketScan: true }));
if (!hasMarketCachedDetail || forceRefresh) {
void ensureCityDetail(cityName, forceRefresh, "market").catch(() => {});
}
@@ -1075,17 +1022,6 @@ export function DashboardStoreProvider({
}));
});
}
- void ensureCityMarketScan(
- cityName,
- forceRefresh || !marketScanByCityName[cacheKey],
- null,
- dateStr,
- )
- .catch(() => {})
- .finally(() => {
- if (selectedCityRef.current !== cityName) return;
- setLoadingState((current) => ({ ...current, marketScan: false }));
- });
},
openHistory,
openTodayModal: async (forceRefresh?: boolean) => {
@@ -1129,7 +1065,6 @@ export function DashboardStoreProvider({
setLoadingState((current) => ({
...current,
futureDeep: needsDetailRefresh,
- marketScan: true,
}));
if (!hasMarketCachedDetail || forceRefresh) {
void ensureCityDetail(
@@ -1138,26 +1073,6 @@ export function DashboardStoreProvider({
"market",
).catch(() => {});
}
- const initialTargetDate =
- cachedDetail?.local_date || selectedForecastDate || null;
- const initialMarketKey = getMarketScanCacheKey(
- cityName,
- initialTargetDate,
- );
- void ensureCityMarketScan(
- cityName,
- forceRefresh || !marketScanByCityName[initialMarketKey],
- null,
- initialTargetDate,
- )
- .catch(() => {})
- .finally(() => {
- if (selectedCityRef.current !== cityName) return;
- setLoadingState((current) => ({
- ...current,
- marketScan: false,
- }));
- });
void ensureCityDetail(
cityName,
needsDetailRefresh,
@@ -1189,7 +1104,6 @@ export function DashboardStoreProvider({
refreshAll,
refreshProAccess,
refreshSelectedCity,
- selectedMarketScan,
selectedCity,
selectedDetail,
selectedForecastDate,
@@ -1197,7 +1111,6 @@ export function DashboardStoreProvider({
setMapInteractionActive: setIsMapInteracting,
setForecastDate: (dateStr: string | null) =>
setSelectedForecastDate(dateStr),
- marketScanByCityName,
}),
[
cities,
@@ -1208,8 +1121,6 @@ export function DashboardStoreProvider({
isPanelOpen,
loadingState,
proAccess,
- marketScanByCityName,
- selectedMarketScan,
selectedCity,
selectedDetail,
selectedForecastDate,
@@ -1259,3 +1170,4 @@ export function useHistoryData(name?: string | null) {
meta: key ? store.historyState.metaByCity[key] || null : null,
};
}
+
diff --git a/frontend/lib/dashboard-client.ts b/frontend/lib/dashboard-client.ts
index 1f4e5845..614d9ff6 100644
--- a/frontend/lib/dashboard-client.ts
+++ b/frontend/lib/dashboard-client.ts
@@ -3,7 +3,6 @@
import {
CityDetail,
CityListItem,
- MarketScan,
CitySummary,
HistoryPayload,
} from "@/lib/dashboard-types";
@@ -13,7 +12,6 @@ const CACHE_TTL_MS = 5 * 60 * 1000;
const pendingCityDetailRequests = new Map>();
const pendingHistoryRequests = new Map>();
const pendingCitySummaryRequests = new Map>();
-const pendingMarketScanRequests = new Map>();
type CityCacheMeta = {
cachedAt: number;
@@ -195,64 +193,6 @@ export const dashboardClient = {
);
},
- async getCityMarketScan(
- cityName: string,
- options?: {
- force?: boolean;
- marketSlug?: string | null;
- targetDate?: string | null;
- },
- ) {
- const force = options?.force ?? false;
- const marketSlug = options?.marketSlug || null;
- const targetDate = options?.targetDate || null;
- if (!force) {
- const requestKey = `${cityName}::cached::${marketSlug || "-"}::${
- targetDate || "-"
- }`;
- const existing = pendingMarketScanRequests.get(requestKey);
- if (existing) {
- return existing;
- }
-
- const params = new URLSearchParams({
- force_refresh: "false",
- });
- if (marketSlug) {
- params.set("market_slug", marketSlug);
- }
- if (targetDate) {
- params.set("target_date", targetDate);
- }
-
- const request = fetchJson<{ market_scan?: MarketScan }>(
- `/api/city/${normalizeCityName(cityName)}/market-scan?${params.toString()}`,
- )
- .then((data) => data.market_scan || null)
- .finally(() => {
- pendingMarketScanRequests.delete(requestKey);
- });
-
- pendingMarketScanRequests.set(requestKey, request);
- return request;
- }
-
- const params = new URLSearchParams({
- force_refresh: "true",
- _ts: String(Date.now()),
- });
- if (marketSlug) {
- params.set("market_slug", marketSlug);
- }
- if (targetDate) {
- params.set("target_date", targetDate);
- }
-
- return fetchJson<{ market_scan?: MarketScan }>(
- `/api/city/${normalizeCityName(cityName)}/market-scan?${params.toString()}`,
- ).then((data) => data.market_scan || null);
- },
-
async getHistory(cityName: string, options?: { includeRecords?: boolean }) {
const includeRecords = options?.includeRecords === true;
const requestKey = `${normalizeCityName(cityName)}::${
diff --git a/frontend/lib/dashboard-types.ts b/frontend/lib/dashboard-types.ts
index cb9cca89..13ac8776 100644
--- a/frontend/lib/dashboard-types.ts
+++ b/frontend/lib/dashboard-types.ts
@@ -556,3 +556,4 @@ export interface DashboardState {
historyState: HistoryState;
proAccess: ProAccessState;
}
+
diff --git a/web/routes.py b/web/routes.py
index 62660c7b..3ecc211e 100644
--- a/web/routes.py
+++ b/web/routes.py
@@ -600,21 +600,7 @@ async def auth_me(request: Request):
user_id,
respect_requirement=False,
)
- if (
- not latest_subscription
- and getattr(PAYMENT_CHECKOUT, "enabled", False)
- ):
- try:
- PAYMENT_CHECKOUT.reconcile_latest_intent(user_id)
- latest_subscription = SUPABASE_ENTITLEMENT.get_latest_active_subscription(
- user_id,
- respect_requirement=False,
- )
- except Exception:
- latest_subscription = SUPABASE_ENTITLEMENT.get_latest_active_subscription(
- user_id,
- respect_requirement=False,
- )
+
latest_known_subscription = latest_subscription
if not latest_known_subscription:
latest_known_subscription = (
@@ -1119,3 +1105,4 @@ async def city_market_scan(
market_slug,
target_date,
)
+