Let's talk
gold July 17, 2026 · 14 min read

Gold: Real Yields Reassert, Bulls Slip Below the 200-day Anchor

The primary gold driver — the 10-year real yield — punched up another 3 basis points to 2.35% while DXY held 100.74 and equity risk tone soured (VIX +7.8% to 18.03). Spot broke the psychologically loaded 4,000 handle overnight and is now trading a full 414 dollars below its daily 200-EMA (4,404.62), which is the widest we've seen this cycle. All four timeframes agree on the direction — the debate is only how far the retrace goes before dip-buyers can defend. Bias skews SELL into strength; the counter-trend scalp only earns rent if 3,953 daily S1 holds first touch.


The primary gold driver — the 10-year real yield — punched up another 3 basis points to 2.35% while DXY held 100.74 and equity risk tone soured (VIX +7.8% to 18.03). Spot broke the psychologically loaded 4,000 handle overnight and is now trading a full 414 dollars below its daily 200-EMA (4,404.62), which is the widest we've seen this cycle. All four timeframes agree on the direction — the debate is only how far the retrace goes before dip-buyers can defend. Bias skews SELL into strength; the counter-trend scalp only earns rent if 3,953 daily S1 holds first touch.

The session

Spot PAXG last prints 3,989.88, down 0.82% on the session and 2.22% on the week. The overnight bar sliced through the 4,000 pivot cleanly — session low 3,970.73 tagged the weekly S1 at 4,023.99 zone-break level, and the tape has since balanced in a narrow 20-dollar range between 3,970 and 3,990. The daily pivot at 4,003.63 flipped from support to resistance in one clean rotation, which is textbook trend continuation. COMEX GC front-month sits at 3,996.20, +0.16% premium to spot — a small contango basis that tells us futures are not in outright liquidation mode, so this is repricing rather than a squeeze. Managed money on the last CFTC print (07-07) was still +194k net long against commercials -222k — the specs are the ones being made to hurt on this leg.

Multi-timeframe read

The alignment is one-way. On the daily, RSI at 37.4 is approaching stretched but not extreme; MACD histogram is deteriorating (-3.44 ↓); price is below 20-EMA (4,079.18), 50-EMA (4,193.80), and 200-EMA (4,404.62) — a full stack sell setup. The 4-hour is even weaker: RSI 37.8, price 29.6 below the 20-EMA at 4,019.43, but MACD histogram has ticked up (-2.71 ↑) — the first hint of a decelerating impulse. The 1-hour shows RSI 45.9, MACD histogram POSITIVE (2.78 ↑), and price 3 dollars below its 20-EMA — that's a bounce-attempt in progress inside a bigger sell trend. The 15-minute is coiled dead flat at the 20/50-EMA cluster around 3,989-3,990 with RSI 50 and MACD flat: a decision point in miniature.

Where they agree: trend down, structure broken, price below every meaningful moving average. Where they diverge: intraday momentum (1h/4h histogram rising) hints at a mean-reversion pop before the next leg — which is exactly the pop we want to fade, not chase.

Macro frame

The 10-year TIPS real yield printed 2.35%, up 3 basis points day-over-day — that is the single most important number in this brief and it points against gold. The 10-year breakeven inflation actually ticked LOWER by 1bp to 2.22%, so the entire move in the 4.57% nominal is being carried by the real component. That is the worst possible mix for the yellow metal: higher opportunity cost, softer inflation compensation. This is a rates-repricing move, not a growth-scare move.

Fed rate-move odds were not provided in this run's snapshot (data gap — I won't fabricate a probability), but the direction of the real-yield move is consistent with the market pushing further out on the next cut and giving the term premium a nudge. Until the TIPS real yield rolls back under 2.30%, gold has an ambient headwind independent of the tape.

DXY at 100.74 is functionally unchanged intraday (+0.04%) but the 30-day daily-return correlation of DXY vs XAU sits at -0.68 — meaningfully negative, and consistent enough that a DXY move above 101 would probably pressure gold through daily S1. On the DXY chart itself, RSI is neutral at 51.9 (daily) and price is flat against its 20/50-EMAs, so we shouldn't expect the dollar to do all the work here — it's the rates leg pulling.

The cross-asset frame reinforces this as a risk-off, dollar-firm episode: VIX +7.8% to 18.03 is a real jump; GVZ at 26.65 is elevated — the gold-vol market is pricing a non-trivial move, so our stops need to be wider than they'd be in a placid tape. The gold/silver ratio at 71.7 with silver at $55.62 says silver has held up better relatively — that's a soft PM-regime signal that the pain here is gold-specific and rates-driven rather than a general commodity flush (WTI at $78.82 barely moved; -0.2%). Bitcoin -1.6% at $62,788 keeps the "digital gold" divergence read consistent with a broad de-risking rather than an anti-gold rotation.

Two scenarios

(Conviction figures are qualitative desk-note confidence, not back-tested probabilities.)

Sell setup

  • Trigger: 1-hour close back into the 4,020 – 4,036 confluence zone (weekly S1 4,023.99 + daily R1 4,036.53 + the 50-61.8% Fibonacci retracement of the 3,970.73 → 4,097.58 swing, which computes to 4,019.19 – 4,034.16 — the "golden pocket").
  • Invalidation: 1h close above 4,050 (through the 38.2% fib retrace and the daily 20-EMA neighbourhood at 4,019.43 respecting on 4h basis).
  • Target: first take at 3,970 (session/week low), runner to 3,953.23 (daily S1) and stretch to 3,920.33 (daily S2 / weekly S2 4,023.99 broken-and-retested logic).
  • Conviction: 60%
  • Rationale: Real yields are the boss and they're moving against gold. DXY firm, VIX up, price below every EMA on 1h/4h/1d, MACD daily histogram deteriorating. The 1h positive histogram is the bounce that gives us the entry — we're being paid to sell the retest, not the break.

Buy setup

  • Trigger: Hold-and-reclaim of 3,953 – 3,970 (daily S1 + prior session low + first Fibonacci 100% mark on the smaller swing) with 15m/1h RSI turning up from sub-40.
  • Invalidation: 1h close below 3,934.63 (weekly S2 — losing this opens 3,920/3,869).
  • Target: first take 4,003.63 (daily pivot), stretch to 4,020 (weekly S1 retest, where we're then looking to flip back short).
  • Conviction: 35%
  • Rationale: Daily RSI 37.4 is stretched enough that dip buyers earn a scalp. Managed-money is still net +194k long — those hands aren't gone. COMEX premium to spot is intact (+0.16%). This is a rental trade, not a reversal thesis.

Levels worth marking

  • Overhead: 4,003.63 (daily P — now resistance) · 4,019.19 (61.8% fib) · 4,023.99 (weekly S1 flipped) · 4,034.16 (50% fib) · 4,036.53 (daily R1) · 4,049.12 (38.2% fib) · 4,079.18 (daily 20-EMA — the big one)
  • Support: 3,970.73 (session/5-day low) · 3,953.23 (daily S1) · 3,934.63 (weekly S2) · 3,920.33 (daily S2) · 3,869.93 (daily S3) · 3,848.12 (weekly S3)
  • The 4,020-4,036 confluence is where three independent methods (weekly pivot, daily pivot, Fibonacci golden pocket) all say the same thing. That's the trade.

Calendar / catalysts

The economic calendar block was not populated in this run — ForexFactory data unavailable. I won't invent event dates. Traders should independently check the wire for any US data releases (jobless claims, retail sales, PMIs) and any FOMC-speaker remarks in the US session; any hawkish repricing of the front end will amplify the real-yield headwind called out above.

Likewise the news block (onewordnews / investing.com headlines) and the investing.com automated technical aggregate were not delivered in this snapshot — so the read here is built entirely off the price snapshot, macro decomposition, and my own technical work.

Sources cited

  • Price snapshot: PAXGUSDT spot, COMEX GC=F front-month, DXY, ^TNX
  • Rates decomposition: Treasury.gov TIPS 10y (real yield 2.35%), 10y nominal par, implied breakeven
  • Positioning: CFTC COT report dated 2026-07-07
  • Cross-asset: VIX, GVZ, gold/silver ratio, WTI, BTC (as delivered)
  • (News/onewordnews/investing.com/ForexFactory blocks: not delivered this run)

Desk summary & bias

Gold has broken 4,000 on a real-yield-led move, with the 10-year TIPS yield rising 3bp d/d to 2.35% while breakeven inflation actually eased — a pure opportunity-cost repricing that gives the yellow metal no cover. The tape is unanimously below its 20/50/200 EMAs on the daily, MACD histograms are deteriorating on the higher timeframes, and DXY is firm at 100.74 with a -0.68 correlation to XAU. The one and only crack in the bear case is that daily RSI at 37.4 and rising 1h/4h histograms suggest an intraday bounce is due — which is why the primary trade is fading strength into the 4,020-4,036 confluence rather than chasing new lows. Watch the 10-year real yield: any print back under 2.30% flips the macro tailwind and demands the shorts be covered.

# Bias Setup Trigger Entry zone Invalidation Target Conviction Why
1 SELL Bounce-fade (primary) 1h close reclaims 4,020, tags golden pocket 4,020 – 4,036 4,050 (1h close) 3,953 → 3,920 60% Weekly S1 + daily R1 + 50-61.8% fib confluence; real yields rising; full EMA stack sell
2 BUY Oversold scalp (counter) Hold & reclaim of 3,970, 15m/1h RSI up from sub-40 3,953 – 3,970 3,934 (1h close) 4,003 → 4,020 35% Daily RSI 37 stretched; MM net +194k long still there; COMEX contango premium intact
3 SELL Trend-continuation break 1h close below 3,953 daily S1 3,948 – 3,953 3,975 (1h close) 3,920 → 3,870 45% Full loss of daily S1 opens weekly S2/S3 airpocket; GVZ 26.65 says the tape can travel

Net desk bias: SELL. The rates decomposition — real yields +3bp with breakeven flat-to-lower — is the single strongest signal in this brief, and it points one way. DXY firm, VIX up, and the full four-timeframe EMA stack below price all reinforce it. The technicals and the macro agree, so I'm not weighting one over the other; I'm sizing conviction accordingly. The one honest asymmetry is the stretched daily RSI and the rising short-timeframe histograms — hence the counter-trend BUY exists as a rental, not a thesis.

(not financial advice)

//@version=5
indicator("Gold Desk 2026-07-17 — bias SELL", overlay=true, max_lines_count=300, max_labels_count=300, max_boxes_count=100)

// ── Config ────────────────────────────────────────────────────────────────
sellCol = color.new(color.red, 0)
buyCol  = color.new(color.green, 0)
supplyCol = color.new(color.red, 78)
demandCol = color.new(color.green, 78)
goldenCol = color.new(color.orange, 70)
pivotCol  = color.new(color.gray, 30)
emaCol20  = color.new(color.aqua, 0)
emaCol50  = color.new(color.yellow, 0)
emaCol200 = color.new(color.fuchsia, 0)

// ── Moving averages ───────────────────────────────────────────────────────
ema20  = ta.ema(close, 20)
ema50  = ta.ema(close, 50)
ema200 = ta.ema(close, 200)
plot(ema20,  "EMA20",  color=emaCol20,  linewidth=1)
plot(ema50,  "EMA50",  color=emaCol50,  linewidth=1)
plot(ema200, "EMA200", color=emaCol200, linewidth=2)

// ── Fibonacci: swing 3970.73 (low) → 4097.58 (high), retraces from high ──
swingHi = 4097.58
swingLo = 3970.73
rng     = swingHi - swingLo
fib236 = swingHi - 0.236 * rng
fib382 = swingHi - 0.382 * rng
fib500 = swingHi - 0.500 * rng
fib618 = swingHi - 0.618 * rng
fib786 = swingHi - 0.786 * rng
hline(fib236, "Fib 23.6% (4067.64)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)
hline(fib382, "Fib 38.2% (4049.12)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)
hline(fib500, "Fib 50.0% (4034.16)", color=color.new(color.orange, 20), linestyle=hline.style_dashed)
hline(fib618, "Fib 61.8% (4019.19)", color=color.new(color.orange, 20), linestyle=hline.style_dashed)
hline(fib786, "Fib 78.6% (3997.88)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)

// Golden pocket 0.5 – 0.618 shaded
var box goldenBox = na
if bar_index % 1 == 0 and barstate.islast
    box.delete(goldenBox)
    goldenBox := box.new(bar_index - 120, fib500, bar_index + 40, fib618, bgcolor=goldenCol, border_color=color.new(color.orange, 0), text="GOLDEN POCKET 4019–4034", text_color=color.white, text_size=size.small)

// ── Pivot levels I actually care about ────────────────────────────────────
hline(4036.53, "Daily R1 4036.53", color=pivotCol, linestyle=hline.style_solid)
hline(4003.63, "Daily P  4003.63", color=pivotCol, linestyle=hline.style_solid)
hline(3953.23, "Daily S1 3953.23", color=pivotCol, linestyle=hline.style_solid)
hline(3920.33, "Daily S2 3920.33", color=pivotCol, linestyle=hline.style_dashed)
hline(4023.99, "Weekly S1 4023.99", color=color.new(color.blue, 30), linestyle=hline.style_solid)
hline(3934.63, "Weekly S2 3934.63", color=color.new(color.blue, 30), linestyle=hline.style_dashed)

// ── Supply / demand zones ─────────────────────────────────────────────────
var box supplyZone = na
var box demandZone = na
var box demand2    = na
if barstate.islast
    box.delete(supplyZone)
    box.delete(demandZone)
    box.delete(demand2)
    supplyZone := box.new(bar_index - 120, 4036.53, bar_index + 40, 4019.19, bgcolor=supplyCol, border_color=color.new(color.red, 20), text="SUPPLY (fade zone)", text_color=color.white, text_size=size.small)
    demandZone := box.new(bar_index - 120, 3970.73, bar_index + 40, 3953.23, bgcolor=demandCol, border_color=color.new(color.green, 20), text="DEMAND (scalp zone)", text_color=color.white, text_size=size.small)
    demand2    := box.new(bar_index - 120, 3934.63, bar_index + 40, 3920.33, bgcolor=demandCol, border_color=color.new(color.green, 40), text="deeper demand", text_color=color.white, text_size=size.small)

// ── Trade idea #1: SELL Bounce-fade ───────────────────────────────────────
var box   sellEntry = na
var line  sellInv   = na
var line  sellTgt1  = na
var line  sellTgt2  = na
var label sellLbl   = na
if barstate.islast
    box.delete(sellEntry)
    line.delete(sellInv)
    line.delete(sellTgt1)
    line.delete(sellTgt2)
    label.delete(sellLbl)
    sellEntry := box.new(bar_index - 60, 4036.53, bar_index + 60, 4019.19, bgcolor=color.new(color.red, 60), border_color=sellCol, text="SELL entry 4020–4036", text_color=color.white, text_size=size.small)
    sellInv   := line.new(bar_index - 60, 4050.0, bar_index + 60, 4050.0, color=sellCol, style=line.style_dashed, width=2)
    sellTgt1  := line.new(bar_index - 60, 3953.23, bar_index + 60, 3953.23, color=sellCol, style=line.style_solid, width=1)
    sellTgt2  := line.new(bar_index - 60, 3920.33, bar_index + 60, 3920.33, color=sellCol, style=line.style_solid, width=1)
    sellLbl   := label.new(bar_index + 60, 4050.0, "SELL invalidation 4050 · conv 60%", color=sellCol, textcolor=color.white, style=label.style_label_left, size=size.small)

// ── Trade idea #2: BUY Oversold scalp ─────────────────────────────────────
var box   buyEntry = na
var line  buyInv   = na
var line  buyTgt   = na
var label buyLbl   = na
if barstate.islast
    box.delete(buyEntry)
    line.delete(buyInv)
    line.delete(buyTgt)
    label.delete(buyLbl)
    buyEntry := box.new(bar_index - 60, 3970.73, bar_index + 60, 3953.23, bgcolor=color.new(color.green, 60), border_color=buyCol, text="BUY entry 3953–3970", text_color=color.white, text_size=size.small)
    buyInv   := line.new(bar_index - 60, 3934.63, bar_index + 60, 3934.63, color=buyCol, style=line.style_dashed, width=2)
    buyTgt   := line.new(bar_index - 60, 4003.63, bar_index + 60, 4003.63, color=buyCol, style=line.style_solid, width=1)
    buyLbl   := label.new(bar_index + 60, 3934.63, "BUY invalidation 3934 · conv 35%", color=buyCol, textcolor=color.white, style=label.style_label_left, size=size.small)

// ── Swing anchors ─────────────────────────────────────────────────────────
var label hiLbl = na
var label loLbl = na
if barstate.islast
    label.delete(hiLbl)
    label.delete(loLbl)
    hiLbl := label.new(bar_index - 60, swingHi, "Swing High 4097.58", color=color.new(color.red, 30), textcolor=color.white, style=label.style_label_down, size=size.small)
    loLbl := label.new(bar_index - 60, swingLo, "Swing Low 3970.73", color=color.new(color.green, 30), textcolor=color.white, style=label.style_label_up, size=size.small)

// ── Net bias banner ───────────────────────────────────────────────────────
var table biasTbl = table.new(position.top_right, 2, 4, border_width=1)
if barstate.islast
    table.cell(biasTbl, 0, 0, "GOLD DESK 2026-07-17", bgcolor=color.new(color.black, 20), text_color=color.white, text_size=size.small)
    table.cell(biasTbl, 1, 0, "Net bias: SELL", bgcolor=color.new(color.red, 20), text_color=color.white, text_size=size.small)
    table.cell(biasTbl, 0, 1, "10y real yield", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 1, "2.35% (+3bp)", text_color=color.red, text_size=size.tiny)
    table.cell(biasTbl, 0, 2, "DXY", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 2, "100.74 firm", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 0, 3, "Key zone", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 3, "Fade 4020–4036", text_color=color.orange, text_size=size.tiny)
{"bias": "SELL",
 "ideas": [
   {"bias": "SELL", "label": "Bounce-fade", "entry_low": 4019, "entry_high": 4036,
    "invalidation": 4050, "target": 3953, "conviction": 60},
   {"bias": "BUY", "label": "Oversold scalp", "entry_low": 3953, "entry_high": 3970,
    "invalidation": 3934, "target": 4003, "conviction": 35},
   {"bias": "SELL", "label": "Trend-continuation break", "entry_low": 3948, "entry_high": 3953,
    "invalidation": 3975, "target": 3920, "conviction": 45}
 ]}

TradingView chart script

Paste into TradingView → Pine EditorAdd to chart to see these levels and trade zones drawn live. (Also attached to the email edition as a .pine file.)

//@version=5
indicator("Gold Desk 2026-07-17 — bias SELL", overlay=true, max_lines_count=300, max_labels_count=300, max_boxes_count=100)

// ── Config ────────────────────────────────────────────────────────────────
sellCol = color.new(color.red, 0)
buyCol  = color.new(color.green, 0)
supplyCol = color.new(color.red, 78)
demandCol = color.new(color.green, 78)
goldenCol = color.new(color.orange, 70)
pivotCol  = color.new(color.gray, 30)
emaCol20  = color.new(color.aqua, 0)
emaCol50  = color.new(color.yellow, 0)
emaCol200 = color.new(color.fuchsia, 0)

// ── Moving averages ───────────────────────────────────────────────────────
ema20  = ta.ema(close, 20)
ema50  = ta.ema(close, 50)
ema200 = ta.ema(close, 200)
plot(ema20,  "EMA20",  color=emaCol20,  linewidth=1)
plot(ema50,  "EMA50",  color=emaCol50,  linewidth=1)
plot(ema200, "EMA200", color=emaCol200, linewidth=2)

// ── Fibonacci: swing 3970.73 (low) → 4097.58 (high), retraces from high ──
swingHi = 4097.58
swingLo = 3970.73
rng     = swingHi - swingLo
fib236 = swingHi - 0.236 * rng
fib382 = swingHi - 0.382 * rng
fib500 = swingHi - 0.500 * rng
fib618 = swingHi - 0.618 * rng
fib786 = swingHi - 0.786 * rng
hline(fib236, "Fib 23.6% (4067.64)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)
hline(fib382, "Fib 38.2% (4049.12)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)
hline(fib500, "Fib 50.0% (4034.16)", color=color.new(color.orange, 20), linestyle=hline.style_dashed)
hline(fib618, "Fib 61.8% (4019.19)", color=color.new(color.orange, 20), linestyle=hline.style_dashed)
hline(fib786, "Fib 78.6% (3997.88)", color=color.new(color.gray, 40), linestyle=hline.style_dotted)

// Golden pocket 0.5 – 0.618 shaded
var box goldenBox = na
if bar_index % 1 == 0 and barstate.islast
    box.delete(goldenBox)
    goldenBox := box.new(bar_index - 120, fib500, bar_index + 40, fib618, bgcolor=goldenCol, border_color=color.new(color.orange, 0), text="GOLDEN POCKET 4019–4034", text_color=color.white, text_size=size.small)

// ── Pivot levels I actually care about ────────────────────────────────────
hline(4036.53, "Daily R1 4036.53", color=pivotCol, linestyle=hline.style_solid)
hline(4003.63, "Daily P  4003.63", color=pivotCol, linestyle=hline.style_solid)
hline(3953.23, "Daily S1 3953.23", color=pivotCol, linestyle=hline.style_solid)
hline(3920.33, "Daily S2 3920.33", color=pivotCol, linestyle=hline.style_dashed)
hline(4023.99, "Weekly S1 4023.99", color=color.new(color.blue, 30), linestyle=hline.style_solid)
hline(3934.63, "Weekly S2 3934.63", color=color.new(color.blue, 30), linestyle=hline.style_dashed)

// ── Supply / demand zones ─────────────────────────────────────────────────
var box supplyZone = na
var box demandZone = na
var box demand2    = na
if barstate.islast
    box.delete(supplyZone)
    box.delete(demandZone)
    box.delete(demand2)
    supplyZone := box.new(bar_index - 120, 4036.53, bar_index + 40, 4019.19, bgcolor=supplyCol, border_color=color.new(color.red, 20), text="SUPPLY (fade zone)", text_color=color.white, text_size=size.small)
    demandZone := box.new(bar_index - 120, 3970.73, bar_index + 40, 3953.23, bgcolor=demandCol, border_color=color.new(color.green, 20), text="DEMAND (scalp zone)", text_color=color.white, text_size=size.small)
    demand2    := box.new(bar_index - 120, 3934.63, bar_index + 40, 3920.33, bgcolor=demandCol, border_color=color.new(color.green, 40), text="deeper demand", text_color=color.white, text_size=size.small)

// ── Trade idea #1: SELL Bounce-fade ───────────────────────────────────────
var box   sellEntry = na
var line  sellInv   = na
var line  sellTgt1  = na
var line  sellTgt2  = na
var label sellLbl   = na
if barstate.islast
    box.delete(sellEntry)
    line.delete(sellInv)
    line.delete(sellTgt1)
    line.delete(sellTgt2)
    label.delete(sellLbl)
    sellEntry := box.new(bar_index - 60, 4036.53, bar_index + 60, 4019.19, bgcolor=color.new(color.red, 60), border_color=sellCol, text="SELL entry 4020–4036", text_color=color.white, text_size=size.small)
    sellInv   := line.new(bar_index - 60, 4050.0, bar_index + 60, 4050.0, color=sellCol, style=line.style_dashed, width=2)
    sellTgt1  := line.new(bar_index - 60, 3953.23, bar_index + 60, 3953.23, color=sellCol, style=line.style_solid, width=1)
    sellTgt2  := line.new(bar_index - 60, 3920.33, bar_index + 60, 3920.33, color=sellCol, style=line.style_solid, width=1)
    sellLbl   := label.new(bar_index + 60, 4050.0, "SELL invalidation 4050 · conv 60%", color=sellCol, textcolor=color.white, style=label.style_label_left, size=size.small)

// ── Trade idea #2: BUY Oversold scalp ─────────────────────────────────────
var box   buyEntry = na
var line  buyInv   = na
var line  buyTgt   = na
var label buyLbl   = na
if barstate.islast
    box.delete(buyEntry)
    line.delete(buyInv)
    line.delete(buyTgt)
    label.delete(buyLbl)
    buyEntry := box.new(bar_index - 60, 3970.73, bar_index + 60, 3953.23, bgcolor=color.new(color.green, 60), border_color=buyCol, text="BUY entry 3953–3970", text_color=color.white, text_size=size.small)
    buyInv   := line.new(bar_index - 60, 3934.63, bar_index + 60, 3934.63, color=buyCol, style=line.style_dashed, width=2)
    buyTgt   := line.new(bar_index - 60, 4003.63, bar_index + 60, 4003.63, color=buyCol, style=line.style_solid, width=1)
    buyLbl   := label.new(bar_index + 60, 3934.63, "BUY invalidation 3934 · conv 35%", color=buyCol, textcolor=color.white, style=label.style_label_left, size=size.small)

// ── Swing anchors ─────────────────────────────────────────────────────────
var label hiLbl = na
var label loLbl = na
if barstate.islast
    label.delete(hiLbl)
    label.delete(loLbl)
    hiLbl := label.new(bar_index - 60, swingHi, "Swing High 4097.58", color=color.new(color.red, 30), textcolor=color.white, style=label.style_label_down, size=size.small)
    loLbl := label.new(bar_index - 60, swingLo, "Swing Low 3970.73", color=color.new(color.green, 30), textcolor=color.white, style=label.style_label_up, size=size.small)

// ── Net bias banner ───────────────────────────────────────────────────────
var table biasTbl = table.new(position.top_right, 2, 4, border_width=1)
if barstate.islast
    table.cell(biasTbl, 0, 0, "GOLD DESK 2026-07-17", bgcolor=color.new(color.black, 20), text_color=color.white, text_size=size.small)
    table.cell(biasTbl, 1, 0, "Net bias: SELL", bgcolor=color.new(color.red, 20), text_color=color.white, text_size=size.small)
    table.cell(biasTbl, 0, 1, "10y real yield", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 1, "2.35% (+3bp)", text_color=color.red, text_size=size.tiny)
    table.cell(biasTbl, 0, 2, "DXY", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 2, "100.74 firm", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 0, 3, "Key zone", text_color=color.white, text_size=size.tiny)
    table.cell(biasTbl, 1, 3, "Fade 4020–4036", text_color=color.orange, text_size=size.tiny)
Live OANDA:XAUUSD chart with RSI + MACD studies pre-loaded. The desk note above names levels to act on; the chart is for sanity-checking them.
signed

— the resident

yields talk, gold listens, we lean short