Commit Graph
12 Commits
Author SHA1 Message Date
Brandon Li 3a16af38f6 Merge branch 'vest-fix-timing' into vest-fixes
# Conflicts:
#	lib/reporter.ts
#	lib/vest-class.ts
#	scripts/check-vest.mjs
2026-10-27 14:51:33 -05:00
Brandon LiandClaude Opus 5.5 ef15200e5e Vest: report on Vest's day, and close a leg whose open came back unknown
The reporter and the dashboard take each firm's own trade date
(tradeDateFor), as the engine does: between 5 PM CT and Vest's 8 PM ET
reset the Central date counted the open Vest day as a prior day and as
today's P&L both, and could report a pass the master keeps for good. The
completion check's settle window now follows the client's own roll.

An open whose outcome came back unknown is marked the bot's once a read
shows the position it made, so the market-close guard closes it before a
long closure; an unmarked leg is no longer logged as a hand trade.

A symbol the close gate holds back stays on the candidate board for the
dashboard and the report, and fireLeg holds each account's leg to the
close at its own size, not just the batch lead's. check-vest-client.mjs
drives the guard and the board with every gateway call answered locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:41:20 -05:00
Brandon LiandClaude Opus 5.5 35512cd504 Vest: a claim counts on the fresh day only once Vest dates it there, and a day's second cycle gets its own key
A claim's stage time is now taken before the request goes out (sentAt):
Vest dates it no earlier, so a claim answered just after 20:00 ET no longer
puts the fresh Vest day on stage 2 before the history read shows its
WITHDRAW. One Vest dates after the turn reads as the day before until then,
the cautious way round. Claims saved without it count from their answer.

Completions count one per payout on both paths (completionPlace): the
catch-up's stage no longer counts a Vest day's two claims as one, and a
cycle a day's second claim started carries cycleSeq, so it can be told from
that day's first. The master ignores it until it keys on it; old masters and
old instances are unchanged.

bookHistory's claim bookkeeping (WITHDRAWs, lapse, fund rows, the balance
the books check expects) is now the pure readClaims, tested on the case
that held an account for good: a claim that never went in, read an hour on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:39:13 -05:00
Brandon LiandClaude Opus 5.5 9fe7fc0ea3 Vest: a claim that never reached Vest stops holding the account, and each claim counts once
A claim of unknown outcome now lapses where history is read (bookHistory),
not only in claimPending: its callers wait on historyReady, and the books
check held the account while it counted that claim, so one that never went
in held the account for good. The lapse is the same (no WITHDRAW within 30
min of it, a read an hour on) and is saved; an accepted claim still holds.

An account token that can't be minted means the request never went out:
an order, stop or take-profit reads as not placed, and a claim records no
unknown claim. Only the request's own failure may be "unknown".

A claim Vest dates on the other side of 20:00 ET than it was booked here
no longer leaves a second fund row: the history read takes the local day
back (and the latest fund date with it), and sameDayClaims counts the
claim on Vest's day. A claim Vest doesn't show yet stays on its day.

The report counts payouts one per claim (Vest's WITHDRAWs and the claims
they don't show yet, never fewer than the negative fund rows) for the
account list, payout states and the completion stage, where two claims on
one Vest day were one row. Same-day cycles still share a cycle key; that
needs the master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:14:38 -05:00
Brandon LiandClaude Opus 5.5 ec3e6ea388 Vest: no leg opens into a market close, and accounts plan on Vest's day
Market close: a Vest entry now needs its symbol's market to stay open
for RESET_CLEAR_HOLDS holds of the leg (clearsClose), the clearance the
8 PM ET reset already gets: at the target hold, and at the leg's sized
hold when a leverage cap stretches it. That covers the weekly close and
the daily maintenance hour as Vest's market-hours periods list them.
Before a closure that runs past an 8 PM ET reset (the weekend, a
holiday: longClosure), the bot's own legs still open in the last 5
minutes are closed at market, loudly; a position the bot didn't open is
named in the log and left alone.

Vest's day: Vest accounts are planned, and their legs and entries
counted, on Vest's day (20:00 ET) instead of the Central date
(tradeDateFor, PlatformClient.tradeDate). Between 5 PM CT and the reset
the Central date counted the open Vest day as a prior day and as today's
realized P&L both ($3,000 to go, $800 made: $2,050 left, not $1,900) and
started the leg count over. Other platforms keep the Central date.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:12:27 -05:00
Brandon LiandClaude Opus 5.5 beddbdcf6c Vest: stops reserve 0.02% of the position for slippage, not 0.1%
A platform may now state its own stop slippage share
(PlatformClient.stopSlippageFraction); the daily-loss reserve is the
larger of 10% of the limit and that share of the position. Vest's 9
measured stop-outs filled 0.9 points past the trigger on average and
2.25 at worst, against the ~30 points 0.1% held back. On a $1,400 day
with ~$495k of NDX the stop goes from ~$880 to ~$1,230, and the leg
sizes up for the same hold. Sizing, the placed stop, the dashboard's
next stop and the reset guard all use it; other platforms keep 0.1%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:34:27 -05:00
Brandon LiandClaude Opus 5.5 f0c1569d96 Vest: a split day's next leg gives back the day's gain plus the limit
On a split day the next Vest leg's daily-loss room now adds the day's gain
still in the account to the bot's limit (floorRoom's `gain`), never past
Vest's own floor, and the leg sizes up for the same target hold (Dingo's
next eval leg: $455k -> $842k at 1.5 h, win 28% -> 56%). Other platforms
are unchanged: dllRoom still never widens on a green day.

The gain only widens a leg all but sure to close before Vest's 8 PM ET
reset (resetClearStop, held to the shortest leg the day may carve), and
none of a hand claim's profit counts. The last-stand margin is measured
against the limit, so a green day can't drop a leg's stop.

Around the reset: no new Vest position opens in the last 7 minutes, and
the guard re-fits every 15 s on fresh positions instead of one pass. An
account's positions share the next-day room (stops first, least at risk
first; locked-in profit counts), a hand-moved stop is fitted again, and a
close or profit-side stop that doesn't take is retried or closed.

The dashboard's next stop now reserves for the leg's notional, as fireLeg
does, so DXtrade labels read smaller (display only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 07:21:52 -05:00
Brandon LiandClaude Opus 5.5 016444239e Trades: an open position shows no close price or P&L
Vest's position history gives an open position a placeholder close price
and a $0 P&L (290.25 on an NDX short at 29,538.96). Only a closed
position keeps them now — in the parser, in the stored row (a placeholder
already stored is cleared on the next read) and in the API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 20:02:11 -05:00
Brandon LiandClaude Opus 5.5 a0e7c5b7c2 Vest: relay the login's token, never one account's
The Vest app renews each trading account's own token through the same
POST /v3/auth/refresh as the login's (with that account's refresh token
in the body). The extension relayed those too, and the dashboard kept
whichever token lived longest — so while someone traded in an account on
Vest, Me synced with a token that sees that account alone and dropped
the other 24 from the list.

Extension 0.17.2 skips account renewals. The dashboard also refuses a
token that sees one account and no primary (or names that account in
its claims), keeps the last account list, and falls back to the login's
token it replaced. An account gone from Vest's list no longer leaves a
stale position holding the lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:32:40 -05:00
Brandon LiandClaude Opus 5.5 95cc3bd23f Vest: record every trade, the bot's and outside ones, and list them
Vest's position history (GET /v3/positions) gives each position's size,
open and close price, P&L, fees, funding and why it closed. The client
reads it hourly and a minute after a position closes (or a flat balance
moves) into a new trades table, and stores open positions as they
appear. Vest can't tell an API order from a click, so the bot marks its
own opens and closes as it sends them; an unmarked trade since marking
began was someone else's.

The dashboard's Vest firm row gets a Trades button listing every trade
on its accounts with who opened it and how it closed; the account page
shows its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:23:24 -05:00
Brandon LiandClaude Opus 5.5 32081f3dcf Vest: claim the profit at the target, then trade again the same day
On Vest, a claim lowers the daily-loss floor by the amount claimed. Winning
$1,500 and claiming it leaves $3,000 of room the same day, the full
drawdown. The bot now uses that.

- Payout claims: a scheduler step (runClaims, under the lane mutex, before
  the flat gate) claims every payoutable account that reached its stage's
  target, via a platform that takes payouts by API. The claim is all
  profit above the starting balance. It then clears the account's legs and
  entry outcome for the day so it can trade its next stage. Failures retry
  after 5 minutes. The auto_claim setting 'off' disables it.
- VestClient.claimProfit: POST /v3/capital/withdraw to the login's main
  account (account_type 1 on /v3/accounts). The payout is booked at once:
  today's fund row and the cycle cut, with today's P&L counted from the
  post-claim balance. The history read later rebooks it from Vest's
  WITHDRAW row, and the books check counts a claim until that row shows.
- Same-day stages: an account type can pick its stage by the payouts since
  the firm's last daily reset (stagesSameDay, sameDayClaims). A stage can
  carry its own daily loss limit.
- That limit replaces the type's everywhere room, stops and last stands are
  worked out: the batch, the manual leg, copy trade, the dashboard and the
  report.
- Room from the platform's own floor: dailyLossFloor (Vest) makes the room
  min(stage limit, balance − Vest's floor). A same-day claim that lowers
  the floor therefore frees room, and the room is never more than Vest
  allows. VestClient.dayStartBalance is gone.
- Before the 8 PM ET reset: from 7:55 PM ET, each open Vest position on an
  account with a daily limit is fitted to the room the reset will leave
  (resetSafeStop). Its stop comes in via PUT/POST stop-loss, or the
  position closes when there is no room.
- Checks for same-day stages, the stage limit, floorRoom, the post-claim
  plan, the next reset across both time changes, and resetSafeStop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:56:00 -05:00
Brandon LiandClaude Opus 5.5 96fdd9ca23 Vest platform: a client for Vest Markets, traded on a session the extension relays
Vest (next.vestmarkets.com) is a perps prop firm: index, metal and energy
perps on CME hours, plus stocks, FX and crypto. It joins as a fourth
platform, 'vest', on the DXtrade engine paths. Those are now keyed by
isNotionalPlatform() instead of === 'dxtrade': the firm's own symbols,
percent fees, notional sizing from volatility, and a scheduler lane of its
own.

- Login is relayed, not stored. Vest signs people in with Google through
  Privy and renews the session with a device key the browser won't export.
  Extension 0.17.0's vest-relay.js reads the token the Vest app renews for
  itself (~15 min). It renews nothing, so the tab is never logged out. The
  background script posts that token to POST /api/vest/session, which holds
  it in memory only. With no Vest tab open on a machine that trades Vest,
  the extension opens one.
- The firm's credential is the Vest login's wallet address. The dashboard's
  form offers the relayed wallet with one click.
- VestClient (lib/vest-class.ts), mapped from the web app's traffic and code
  since Vest publishes no API:
  - Reads the capital accounts, balances (free amount plus position
    collateral), positions and open orders with the user token.
  - Mints per-account tokens for orders and transactions.
  - Names accounts for their rules (V50K-E-D3-T10-34, V50K-F-D3-34,
    V25K-I-7) so account-type prefixes can match.
  - Takes Vest's own max-drawdown and daily-loss floors. dayStartBalance =
    floor + the type's limit, so the engine's room is never more than
    Vest's.
  - Uses each symbol's taker fee and margin rate from exchangeInfo, and
    hourly volatility over in-session hours only.
  - Places take-profit and stop as position legs, which Vest cancels as an
    OCO pair.
- Daily P&L and fund rows come from /v3/transactions by Vest's 20:00 ET
  day. A books check holds an account, naming the transaction types, when
  the balance and the transactions disagree.
- scripts/check-vest.mjs (in npm run check): Vest's day across DST, account
  names, parsing, volatility gaps, market hours, the session store.

Not yet run against Vest with a live session: the order and exit bodies
come from the app's code, and the transaction classification from its enum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:19:31 -05:00