Remove Polymarket price integration from dashboard

This commit is contained in:
2569718930@qq.com
2026-04-15 16:30:13 +08:00
parent c55b83a134
commit c4b45be757
5 changed files with 26 additions and 280 deletions
@@ -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}
</div>
<div style={{ position: "relative", minHeight: "120px" }}>
{/* Loading Overlay */}
{store.loadingState.marketScan && (
<div className="market-layer-loading-overlay">
<div
className="loading-spinner"
style={{
marginBottom: "8px",
width: "24px",
height: "24px",
borderWidth: "2px",
}}
/>
{locale === "en-US"
? "Crunching Polymarket Edges..."
: "正在同步市场挂单..."}
</div>
)}
<ProbabilityDistribution
detail={detail}
targetDate={dateStr}
hideTitle
marketScan={marketScan}
/>
</div>
</section>
@@ -1841,7 +1747,6 @@ export function FutureForecastModal() {
detail={detail}
targetDate={dateStr}
hideTitle
marketScan={marketScan}
/>
</section>
<section className="future-modal-section">
@@ -1861,3 +1766,4 @@ export function FutureForecastModal() {
</div>
);
}
+1 -89
View File
@@ -24,7 +24,6 @@ import {
HistoryPayloadMeta,
HistoryState,
LoadingState,
MarketScan,
ProAccessState,
} from "@/lib/dashboard-types";
@@ -46,12 +45,10 @@ interface DashboardStoreValue extends DashboardState {
refreshAll: () => Promise<void>;
refreshProAccess: () => Promise<void>;
refreshSelectedCity: () => Promise<void>;
selectedMarketScan: MarketScan | null;
selectedDetail: CityDetail | null;
selectCity: (cityName: string) => Promise<void>;
setMapInteractionActive: (active: boolean) => void;
setForecastDate: (dateStr: string | null) => void;
marketScanByCityName: Record<string, MarketScan>;
}
const DashboardStoreContext = createContext<DashboardStoreValue | null>(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<string, { cachedAt: number; revision: string }>
>({});
const [marketScanByCityName, setMarketScanByCityName] = useState<
Record<string, MarketScan>
>({});
const [selectedCity, setSelectedCity] = useState<string | null>(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,
};
}
-60
View File
@@ -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<string, Promise<CityDetail>>();
const pendingHistoryRequests = new Map<string, Promise<HistoryPayload>>();
const pendingCitySummaryRequests = new Map<string, Promise<CitySummary>>();
const pendingMarketScanRequests = new Map<string, Promise<MarketScan | null>>();
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)}::${
+1
View File
@@ -556,3 +556,4 @@ export interface DashboardState {
historyState: HistoryState;
proAccess: ProAccessState;
}
+2 -15
View File
@@ -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,
)