@quotient-forecasting/strategy-flip-flat
v0.4.12
Published
Flip-flat Quotient signal strategy for Cassie
Readme
@quotient-forecasting/strategy-flip-flat
The signals strategy for cassie.
It follows published Quotient forecasts. On prediction
markets, it enters where a forecast diverges from the market price, then exits once the
market prices the forecast in, or at the default seven-day maximum hold.
The strategy has no position-count cap by default and ranks competing signals widest edge
first. An optional numeric cap remains available. The default eligible forecast entry edge
is 10–30 percentage points, inclusive. The maximum is configurable; unlimited removes it.
This edge is the gap between the Q forecast and the market reference price, not the quoted
bid/ask spread.
The default prediction-market allocator targets quarter Kelly using current portfolio
equity, subject to a 2.5% cap per market and a 5% cap across markets in the same parent
event. A market that resolves within three days of the entry gets a target 25% smaller
(nearResolutionDays, nearResolutionSizeCutPct); the same cut applies to a legacy
daily-budget entry. Same-side repeat signals can top up only the gap between existing
exposure and the new target, so a reduced position is not topped back up to full size.
Added capital changes future targets automatically. If an existing position is already
above its target or cap, the allocator blocks further additions but does not auto-trim it.
Before a portfolio-mode entry or top-up, the strategy requires at least $2,500 of
held-outcome bid notional within 2¢ of the best bid. This is an entry-only ability-to-exit
check; set --min-exit-depth-2c-usd 0 to disable it. The engine separately sizes the buy
against live ask depth and slippage.
The legacy daily-budget mode remains available. It caps cumulative entry notional from
00:00 to 23:59 UTC; rejected entries do not consume it, and an entry capped by liquidity
or risk consumes only what it actually placed. The UTC reset replenishes entry capacity
without closing anything.
Exits are position-driven, not signal-driven, and the venue book is checked every minute.
By default a position is sold once at most 3pp of held-side forecast edge remains
(convergenceExitPp; null disables it). There is no profit floor and no Q-retreat
condition, so a converged position is sold at whatever the market pays.
Otherwise the default maximum hold is seven days. A stale or unpublished entry signal
cannot suppress either exit. Neither the entry volume floor nor the minimum-notional floor
ever blocks a sell; executable slippage and depth still apply.
Seven-day signal-exit state machine (opt-in)
scenarioExitEnabled: true wraps the convergence exit above in a confirmed state machine
that also reads the latest Q forecast for every held market on the five-minute forecast
cadence. Everything is measured on the contract actually held: for a NO position,
Q, the midpoint, and the executable bid are all mirrored. The immutable entry Q is the
published signal's held-side probability captured when the entry is accepted; it never
changes, however the linked forecast later moves. The current Q is the newest distinct
committed forecast available at evaluation time, identified by its committed timestamp.
Two engine ticks over the same forecast are one observation, never two confirmations.
Exits are evaluated in this order and exactly one reason is emitted:
market_resolved— redeem.q_collapse— held-side Q retreated at least 30pp from entry and remaining edge is at or below 0pp. Immediate, regardless of P&L.adverse_cross— remaining edge at or below 0pp, executable P&L at or below 0%, and two distinct committed forecasts observed with the spread non-positive. A new forecast that restores positive edge resets the run.q_flip— two consecutive distinct committed forecasts below 50% on the held side confirm the flip; exit once remaining edge is at or below 5pp. The confirmation is retained while Q stays flipped, so a later market move can still trigger it. A forecast back above 50% resets it.convergence— remaining held-side edge is at or belowconvergenceExitPp(3pp), with no profit floor and no Q-retreat condition. Because it needs no confirmations and its threshold is wider than the adverse-cross branch's, it subsumes that branch in practice;q_flipstill decides the 3–5pp band.time_stop— position age at or abovemaxHoldDays(7) measured from the actual entry fill, regardless of P&L.
Executable P&L walks the held-side bids for the full position and deducts exitFeeBps.
Each trigger logs entry Q, current Q, midpoint, executable bid, remaining edge, Q retreat,
executable P&L, both confirmation counters, position age, the selected reason, and the
forecast versions that provided the confirmations. The same telemetry rides on the exit
order as provenance. A submitted exit is remembered per position, so repeated evaluation
cannot create duplicate sells; a still-held position resubmits only after exitRetrySec
with no visible order.
Positions that predate the record are seeded from the active same-side signal when one exists; without an entry Q, the collapse branch stays off for that position while the adverse-cross, flip, convergence, and time stop still apply.
cassie strategy <botId> --scenario-exit on
cassie strategy <botId> --convergence-exit-pp 3 --adverse-cross-confirmations 2 \
--q-collapse-pp 30 --flip-confirmations 2 --flip-exit-max-remaining-edge-pp 5 --max-hold-days 7Pending-entry reservation and order provenance
An accepted entry is reserved durably by order id with its market, parent event, and
notional. Polymarket can show an immediate fill in neither positions nor open orders for a
few ticks; the reservation keeps counting against the market and event caps and blocks a
second entry for that market until the venue position absorbs the size, the order rests
visibly, or pendingEntryReservationSec (900) passes with nothing absorbed. Only the part
not yet visible through the position or a resting order is counted, so nothing is counted
twice once the venue catches up.
Every order the engine places persists a decision record (orders:decision:<orderId>)
with the signal id and timestamp, live edge, target, current market and event exposure,
cap headroom, and the limiting cap, or the full exit telemetry. The explanatory subset is
attached to the order alert.
Tune it through the CLI rather than in code:
cassie strategy <botId> --allocation-mode portfolio-kelly \
--kelly-fraction 0.25 --market-cap-pct 2.5 --event-cap-pct 5 \
--min-exit-depth-2c-usd 2500
cassie strategy <botId> --near-resolution-days 3 --near-resolution-size-cut-pct 25
cassie strategy <botId> --daily-budget 100 --position-budget-pct 25
cassie strategy <botId> --max-entry-edge unlimited
cassie strategy <botId> --scenario-exit onEvery entry still passes the engine's per-order, liquidity, slippage, and volume guardrails. Cassie does not cap the quoted bid/ask spread.
