# JOIN & JUMP — Core Market Making Modes

## JOIN Mode (Continuous)

JOIN is the default and only continuous operating mode. The agent places resting limit orders on both sides (YES and NO) of a binary market at the current best bid, profiting the spread when both fill.

### How It Works

1. Read the orderbook for each market
2. Identify the best bid on each side (YES and NO)
3. Place a resting limit order at the best bid price
4. When both sides fill, the agent profits the spread
5. Start a new cycle

### Price Selection (JOIN Logic)

```python
if bid_size > our_resting:
    target = bid  # Others are best, join them
elif second_bid:
    target = second_bid  # We're best, fall back to 2nd
else:
    target = bid  # Only level, stay
```

The agent always joins the queue — never crosses the spread.

### When to Stay in JOIN

- Spread is within configured bounds (min_spread to max_spread)
- Queue position is favorable (front of queue at best bid)
- Market is stable (no rapid price movement)
- Fair value signal confirms current price is reasonable

---

## JUMP (Tactical Per-Market Action)

JUMP is a tactical action, not a persistent mode. The agent pennies ahead of the best bid by 1 cent on a specific market when it determines queue position is unfavorable.

### How It Works

1. Agent detects unfavorable queue position on a specific market
2. Agent triggers JUMP via hotkey `1` (market 1) or `2` (market 2)
3. A one-time penny-ahead target is set: `others_best_bid + 1 cent`
4. If others match or exceed the jump price, jump auto-disables
5. Agent returns to JOIN on that market

### Redis Command

```json
{"action": "toggle_jump", "market_index": 0}
```

### Jump Logic

```python
if jump_active[market_id]:
    if jump_target is None and others_best:
        jump_target = others_best + 1  # penny ahead
    if others_best >= jump_target:
        jump_active[market_id] = False  # they matched, disable
        jump_target = None
    elif jump_target <= 99:
        return jump_target / 100  # use jump price
```

### Semi-Auto JUMP (Luckbot Monitor)

The Luckbot automatically monitors the instance every 10 seconds and triggers JUMP when ALL conditions are met per-market:

1. **Spread > 1c** — spread between yes and no bids in that market exceeds 1 cent
2. **Queue position in last 25%** — our resting order is in the back 25% of total contracts at that price level
3. **Resting < 25% of total** — our order size is less than 25% of all contracts at that bid price

When triggered, the Luckbot sends "jumping bid" notification to Telegram with the spread, queue %, and resting % that caused the jump.

Manual JUMP via `/j1`/`/j2` or natural language still works alongside the monitor.

### When NOT to JUMP

- Spread <= 1c (auto-monitor won't fire)
- Queue position is in the front 75% (we're positioned well)
- Our resting is >= 25% of the total at that level (we're a significant portion of the queue)
- Both sides are filling steadily in JOIN mode (no need to accelerate)

---

## HIGHER-FIRST Mode (2-Market NO Strategy)

Higher-first mode is a market selection strategy for 2-market NO-bid trading. Instead of placing orders on both markets simultaneously, the agent trades one market at a time, starting with whichever has the **higher NO bid** (the more expensive side).

### Why Higher-First?

In a binary event like Team A vs Team B, the team more likely to win has a higher NO bid on the opposing side. For example:

| Market | NO Bid | Meaning |
|--------|--------|---------|
| Team A NO | 87c | Team A is favored (87% implied probability) |
| Team B NO | 18c | Team B is underdog |

By filling the 87c NO side first, the agent holds a position that benefits from **positive time decay**. As the game approaches and the favorite remains ahead, the NO price stays high or increases — meaning the agent's open position appreciates while waiting for the other side to fill.

If instead the agent filled the cheap side (18c) first, the open position would be exposed to **negative time decay** — the favorite's price could move even higher, making the open NO position worth less.

### How It Works

1. **Startup**: Agent reads orderbook for both markets. Selects the market with the higher NO bid as `active_market`.
2. **Place order**: Only places a resting NO bid on the active market.
3. **Wait for fill**: Only checks fills on the active market.
4. **Switch**: When the active market fills `contract_increment` contracts, the agent switches `active_market` to the other market.
5. **Repeat**: The cycle alternates between markets until stopped.

### Resume Rebalancing

If the agent restarts mid-session and positions are imbalanced (e.g., 5 contracts on Market A but only 2 on Market B), the agent detects this and automatically sets the lagging market as `active_market` to catch up before resuming normal alternation.

### Price Selection in Higher-First

Higher-first uses the same JOIN price logic — it joins at the best bid, never crosses the spread. JUMP can still be triggered manually on the active market.

### When to Use Higher-First

- **Basketball (NBA, NCAAMB)**: Highly recommended. Favorites in basketball maintain leads consistently, and scoring is gradual. Time decay works strongly in your favor.
- **Hockey (NHL)**: Useful. Lower-scoring games mean price moves are less frequent between goals.
- **Esports**: Useful for match-winner markets in BO3/BO5 series where favorites hold leads across maps.
- **Crypto intervals**: Can work for CDF-based quoting when one side of the binary is clearly more probable.

### When NOT to Use Higher-First

- When both markets are near 50/50 — there's no meaningful "expensive" side
- When you want maximum fill speed (simultaneous mode fills both sides in parallel)
- Single-market trading (auto1) — not applicable, only for 2-market NO strategy
