docs(launch-watch): add 89109-1 and the launch-time lessons
Sync from SW-ads-global: six benchmark accounts through 89109-1 (2026-09-30), playbook and watch.py thresholds updated to match. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -203,6 +203,10 @@ if prev and prev.get("fresh") != fresh_iso and prev.get("day") == today:
|
||||
alerts.append(f"先赚后亏 {short(name)}({camps[name]['external_campaign_id']}):最近 10 分钟 {ds:.2f}/{dr:.2f},连续 {streak[name]} 个窗口亏;今天 {sp:.2f} ROAS {rv / sp:.2f},峰值 {peak[name]:.2f} → 建议关这个计划")
|
||||
st["snap"] = {"fresh": fresh_iso, "day": today, "camps": {n: v for n, v in agg.items()}}
|
||||
|
||||
# ---- lifecycle clock: stages follow this account's own ramp, not the wall clock (operator 2026-09-30) ----
|
||||
ramp = [h for h in sorted(hsum) if hsum[h][0] >= 20 and h < now.hour]
|
||||
since_ramp = (now.hour + now.minute / 60 - ramp[0]) if ramp else None # hours since the first >= 20 USD hour began
|
||||
|
||||
# ---- rule: budget 80% / 95% while profitable; say whether adding still makes sense ----
|
||||
for name, (sp, rv) in agg.items():
|
||||
c = camps[name]; bud = f(c.get("budget")); ro = rv / sp if sp else 0.0
|
||||
@@ -212,13 +216,12 @@ for name, (sp, rv) in agg.items():
|
||||
key = f"budget{pct}|{c['external_campaign_id']}|{bud}"
|
||||
if key not in rep:
|
||||
rep[key] = {"sp": sp, "ro": ro}
|
||||
late = now.hour >= 17
|
||||
hint = "已过 17 点,手册建议不加" if late else ("ROAS > 1.3,可以加" if ro > 1.3 else "ROAS 不到 1.3,加不加看你")
|
||||
late = since_ramp is not None and since_ramp >= 5
|
||||
hint = "起量已满 5 小时,手册建议不加" if late else ("ROAS > 1.3,可以加" if ro > 1.3 else "ROAS 不到 1.3,加不加看你")
|
||||
alerts.append(f"预算快用完 {short(name)}:今天 {sp:.0f}/{bud:.0f}({sp / bud * 100:.0f}%)ROAS {ro:.2f} → {hint}")
|
||||
break
|
||||
|
||||
# ---- judgement: first full hours after the account starts spending ----
|
||||
ramp = [h for h in sorted(hsum) if hsum[h][0] >= 20 and h < now.hour]
|
||||
if ramp and "judge" not in lc:
|
||||
h0 = ramp[0]; r0 = hsum[h0][1] / hsum[h0][0]
|
||||
verdict = "好户" if r0 >= 1.2 else ("观察" if r0 >= 0.9 else "差户信号")
|
||||
@@ -274,8 +277,8 @@ if hours_in >= 4 and tsp >= 50 and cum < 0.90 and w30 and w30[2] < 0.90:
|
||||
H.append(f"开投 {hours_in:.1f} 小时累计 ROAS {cum:.2f} < 0.90,最近 30 分钟 {w30[2]:.2f} 也 < 0.90")
|
||||
if w30 and w30[0] >= 30 and w30[2] < 0.80:
|
||||
H.append(f"最近 30 分钟放量 {w30[0]:.2f} USD 但 ROAS 只有 {w30[2]:.2f} < 0.80")
|
||||
if (now.hour >= 18 or hours_in >= 8) and w30 and w30[0] >= 3 and w30[2] < 1.0:
|
||||
H.append(f"进入收尾期(18 点后或开投满 8 小时),最近 30 分钟 ROAS {w30[2]:.2f} < 1")
|
||||
if ((since_ramp is not None and since_ramp >= 6) or hours_in >= 8) and w30 and w30[0] >= 3 and w30[2] < 1.0:
|
||||
H.append(f"进入收尾期(起量后满 6 小时或开投满 8 小时),最近 30 分钟 ROAS {w30[2]:.2f} < 1")
|
||||
if tsp >= 50 and cum >= 1.0 and lc.get("was_below_1") and "breakeven" not in lc:
|
||||
lc["breakeven"] = now.strftime("%H:%M")
|
||||
H.append(f"累计 ROAS 回到 1 以上({cum:.2f}),可以考虑收尾锁住")
|
||||
@@ -345,7 +348,7 @@ except (OSError, ValueError, KeyError):
|
||||
|
||||
print("\n".join(alerts) if alerts else "一轮无异常")
|
||||
top = sorted(agg.items(), key=lambda kv: -kv[1][0])[:3]
|
||||
stage = "等量期" if not lc.get("had_spend") and hours_in < 2 else ("判断期" if hours_in < 3 else ("放量期" if now.hour < 18 and hours_in < 8 else "收尾期"))
|
||||
stage = ("等量期" if not ramp else ("判断期" if since_ramp < 3 else ("放量期" if since_ramp < 6 and hours_in < 8 else "收尾期"))) if hours_in < 8 else "收尾期"
|
||||
w30t = f";最近 30 分钟 {w30[0]:.2f}/{w30[1]:.2f} ROAS {w30[2]:.2f}" if w30 else ""
|
||||
lag = f";按天数据落后,TikTok 小时数合计 {h_total:.2f}" if h_total - tsp > 2 else ""
|
||||
print(f"[{stage} {hours_in:.1f}h|{len(camps)} 个在投计划 今天 {tsp:.2f}/{trv:.2f} ROAS {cum:.2f}{w30t};"
|
||||
|
||||
Reference in New Issue
Block a user