Fix ops market opportunity scan snapshot

This commit is contained in:
2569718930@qq.com
2026-07-04 00:07:24 +08:00
parent 7a5fe8b571
commit 59cd48997f
4 changed files with 72 additions and 28 deletions
@@ -57,4 +57,10 @@ export function runTests() {
client.includes("positive_edge_only") && client.includes("显示全部低价"),
"market opportunities page must default to positive edge and allow showing every low-price option",
);
assert(
client.includes("最高买入价") &&
client.includes("最小 Edge") &&
client.includes('showAllLowPrice ? "-1" : minEdge'),
"market opportunities filters must label price versus edge and not edge-filter the show-all-low-price view",
);
}
@@ -112,7 +112,7 @@ export function MarketOpportunitiesPageClient() {
q: query.trim(),
side,
max_price: maxPrice,
min_edge: minEdge,
min_edge: showAllLowPrice ? "-1" : minEdge,
positive_edge_only,
limit: 200,
});
@@ -142,7 +142,7 @@ export function MarketOpportunitiesPageClient() {
</h1>
<p className="mt-1 text-sm text-slate-300">
Ops 使 20¢ Yes/No
Ops 使 Yes/No
</p>
</div>
<Button variant="outline" size="sm" onClick={load} className="gap-1.5">
@@ -161,7 +161,7 @@ export function MarketOpportunitiesPageClient() {
<Card>
<CardHeader className="gap-3">
<CardTitle></CardTitle>
<div className="grid gap-2 md:grid-cols-[minmax(180px,1fr)_120px_120px_120px_auto]">
<div className="grid items-end gap-2 md:grid-cols-[minmax(180px,1fr)_120px_132px_132px_auto]">
<label className="relative block">
<Search className="pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" />
<input
@@ -174,29 +174,42 @@ export function MarketOpportunitiesPageClient() {
placeholder="搜索城市或选项"
/>
</label>
<select
value={side}
onChange={(event) => setSide(event.target.value)}
className="h-9 rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
>
<option value="both">Yes / No</option>
<option value="yes"> Yes</option>
<option value="no"> No</option>
</select>
<input
value={maxPrice}
onChange={(event) => setMaxPrice(event.target.value)}
className="h-9 rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
inputMode="decimal"
aria-label="最高买入价"
/>
<input
value={minEdge}
onChange={(event) => setMinEdge(event.target.value)}
className="h-9 rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
inputMode="decimal"
aria-label="最小 Edge"
/>
<label className="block">
<span className="sr-only"></span>
<select
value={side}
onChange={(event) => setSide(event.target.value)}
className="h-9 w-full rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
>
<option value="both">Yes / No</option>
<option value="yes"> Yes</option>
<option value="no"> No</option>
</select>
</label>
<label className="block">
<span className="mb-1 block text-[11px] font-black uppercase tracking-wide text-slate-500">
</span>
<input
value={maxPrice}
onChange={(event) => setMaxPrice(event.target.value)}
className="h-9 w-full rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
inputMode="decimal"
aria-label="最高买入价"
/>
</label>
<label className="block">
<span className="mb-1 block text-[11px] font-black uppercase tracking-wide text-slate-500">
Edge
</span>
<input
value={minEdge}
onChange={(event) => setMinEdge(event.target.value)}
className="h-9 w-full rounded-md border border-slate-300 bg-white px-2 text-sm font-semibold text-slate-700"
inputMode="decimal"
aria-label="最小 Edge"
/>
</label>
<Button variant="outline" size="sm" onClick={load}>
</Button>
+25
View File
@@ -180,3 +180,28 @@ def test_ops_market_opportunities_degrades_when_quotes_fail(monkeypatch):
assert payload["summary"]["quote_status"] == "unavailable"
assert payload["summary"]["error"] == "polymarket down"
assert payload["rows"] == []
def test_ops_market_opportunities_reuses_prewarmed_terminal_snapshot(monkeypatch):
captured = {}
monkeypatch.setattr(market_opportunities, "_require_ops", lambda _request: {"email": "ops@example.com"})
def fake_scan(filters, *, force_refresh=False):
captured["filters"] = filters
captured["force_refresh"] = force_refresh
return {"rows": [_row()]}
monkeypatch.setattr(market_opportunities, "build_scan_terminal_payload", fake_scan)
monkeypatch.setattr(
market_opportunities,
"_collect_events_and_prices",
lambda rows, _scanner: ({row["city"]: None for row in rows}, {}, "ready"),
)
payload = get_ops_market_opportunities(object(), max_price=0.90, min_edge=0.0)
assert payload["summary"]["scanned_city_count"] == 1
assert captured["force_refresh"] is False
assert captured["filters"]["limit"] == 180
assert captured["filters"]["min_edge_pct"] == 2
assert captured["filters"]["min_liquidity"] == 500
+2 -2
View File
@@ -460,8 +460,8 @@ def get_ops_market_opportunities(
"scan_mode": "tradable",
"min_price": 0.05,
"max_price": 0.95,
"min_edge_pct": 0,
"min_liquidity": 0,
"min_edge_pct": 2,
"min_liquidity": 500,
"market_type": "maxtemp",
"time_range": "today",
"limit": 180,