diff --git a/GATEWAY_ISSUES.md b/GATEWAY_ISSUES.md new file mode 100644 index 00000000..74178569 --- /dev/null +++ b/GATEWAY_ISSUES.md @@ -0,0 +1,561 @@ +# Gateway issues + +Found against gateway `fdad604aa`, Solana mainnet-beta, wallet `82Sgg…yHx5`. +Now merged with the route-unification work on `feat/unified-trading-routes`, which +changed every path these issues live on. + +**Status at a glance** + +| | Issue | State | +|---|---|---| +| GW-1 | Meteora `quote-liquidity` priced the range midpoint | fixed (re-implemented) | +| GW-2 | Raydium AMM `feePct` reported as a fraction | fixed | +| GW-3 | OKX router has no credentials | **needs a decision** — error made legible | +| GW-4 | Native-SOL amounts inflated by the transaction fee | fixed, plus 3 follow-on sites | +| GW-5 | Execute response carried no `poolAddress` | fixed | +| GW-6 | AMM add never returned the DAMM v2 position it created | fixed | +| GW-7 | CLMM/AMM double-counted the fee after GW-4 | fixed (found by GW-4) | +| GW-0 | `poolAddress` pin survived the refactor | no action | +| GW-8 | Nested `data` schemas named but never registered | fixed | +| GW-9 | Request bodies declared inline, so ungeneratable | fixed | +| GW-10 | The reads published a stale shape under the right name | fixed | +| GW-11 | The chain half of `chainNetwork` was decorative on the liquidity routes | fixed | +| GW-12 | Three ways a caller's intent is dropped without an error | **open** | +| GW-13 | The spec guard passes on regressions it claims to catch | fixed | +| GW-14 | No `operationId` and no error responses in the spec | **open** | +| GW-15 | Response component names were never unified | **open** | +| GW-16 | Leftovers the unification did not sweep | **open** | +| GW-17 | `baseTokenAmountAdded` is signed on some connectors, a magnitude on others | fixed | +| GW-18 | pancakeswap-sol's close reports fees and rent as a hardcoded 0 | **open** | +| GW-19 | A hyphen in a token symbol makes its pair unquotable (hummingbot-api) | fixed | +| GW-20 | A DAMM v2 open records the position rent as deposited liquidity | fixed | +| GW-21 | Nothing downstream can close an AMM position, so rent is stranded | fixed (routes collapsed) | +| GW-22 | `position_info` ignored the position it was given (condor) | fixed | +| GW-23 | Money is typed as JSON `number`, so exact decimals do not survive | **open** | +| GW-24 | The committed spec carried a real wallet address and a local port | fixed | +| GW-25 | A narrow in-range CLMM close fails on slippage, and no layer widens it | **open** | + +Seven are open and are written out in full below; the eighteen that are fixed are +summarised under **Fixed — the record**, with the verification each still needs collected +under **Outstanding verification**. + +--- + +## Route changes that affect every issue below + +The trading type is now a path segment and the connector a parameter. The spec went +from 182 paths to 54, and `openapi.json` is generated from the route table by +`pnpm generate:openapi` without a running server. + +| Was | Is | +|---|---| +| `/connectors/{dex}/{type}/*` (128 paths) | removed | +| `/trading/swap/{quote,execute}` | `/trading/router/{quote-swap,execute-quote,execute-swap}` | +| `/connectors/{dex}/{amm,clmm}/quote-swap` | `/trading/{amm,clmm}/quote-swap` | +| `/connectors/{meteora,orca}/clmm/fetch-pools` | `/trading/clmm/fetch-pools` | +| `/trading/clmm/quote-position` | `/trading/clmm/quote-liquidity` | +| `/trading/amm/{add,remove}-liquidity` | `/trading/amm/{add,remove}` | +| — | `/trading/amm/{open,close}` (new) | +| `/chains/{solana,ethereum}/*` (14 paths) | `/chains/{chain}/*` (6) + 2 EVM-only | + +`connector` is now a bare, enum-constrained name (`meteora`, not `meteora/clmm`). +Both callers have since been updated: hummingbot-api vendors this spec, generates its +models from it, and builds every `/trading` request from them; the hummingbot wheel does +the same through `gateway_http_client`. Neither still speaks the old routes. + +--- + +## Outstanding verification + +Carried over from the fixed entries below, none of which has been re-run since it landed. +Everything here needs a container built from current `main`. + +- **GW-1** — quote a Meteora range that does *not* straddle spot; the paired amount should + follow the active bin, not the midpoint. +- **GW-2** — read `pool-info` for a Raydium v4 pool and a CPMM pool; both should report a + percent. +- **GW-4** — repeat three 0.01 SOL swaps; `input_amount` should be 0.01 exactly, with the + fee reported separately. +- **GW-6** — open a DAMM v2 position via `/trading/amm/add` with no `positionAddress` and + confirm the response names the position it created. +- **GW-17** — repeat the Raydium add/remove round trip and read + `POST /gateway/amm/events/search`; both rows should be positive and net to `remove − add`. + Rows written before the fix keep their old signs. +- **GW-22** — the position opened for GW-20, `F1YcTMd6…`, is still open and still holds its + rent; `position_info` on it should answer about it alone. + +--- + +## Still open + +In full, worst first. Only GW-18 is a wrong number; the rest are ways a wrong request is +accepted quietly or a right one is described badly, and GW-3 is a decision rather than a +fix. GW-12 is being fixed in a parallel session. + +--- + +## GW-18 — pancakeswap-sol's close reports fees and rent as a hardcoded 0 +**Status: open.** One connector, one route. Found 2026-08-19 while confirming that a +`collect_fees` result of 0/0 was a real zero rather than a missing field. + +`pancakeswap-sol/clmm-routes/closePosition.ts:127`: + +```ts +baseTokenAmountRemoved: Math.abs(baseTokenChange), // the whole wallet delta +quoteTokenAmountRemoved: Math.abs(quoteTokenChange), +baseFeeAmountCollected: 0, // Included in balance changes +quoteFeeAmountCollected: 0, // Included in balance changes +positionRentRefunded: 0, // Position rent refund (simplified) +``` + +The comment is accurate about the mechanism and that is the problem: the fees really are +inside the balance change, so closing a position with pending fees reports fees of 0 and a +principal inflated by exactly those fees, plus rent of 0. Every other connector separates +them: + +| Connector | fees on close | rent on close | +|---|---|---| +| meteora, orca, raydium | real amounts | real amount | +| uniswap, pancakeswap | real amounts | n/a (no rent on EVM) | +| **pancakeswap-sol** | **always 0** | **always 0** | + +hummingbot-api stores the two fields separately in its CLOSE event and position +accounting, so on this connector fee income is recorded as zero forever and principal +returned reads high — with no error anywhere. + +**A fix was attempted and abandoned deliberately.** Copying `orca/closePosition.ts` does +not work here. `extractInnerTransferAmounts` groups transfers by *top-level instruction*, +which separates Orca's `collectFees` from its `decreaseLiquidity` because they are two +instructions. Pancakeswap-sol builds raw instructions itself, and Raydium-style +`decrease_liquidity_v2` moves principal and fees inside one instruction, so the grouping +returns them already summed. Nor does the position account help: `parsePositionData` reads +only `liquidity`, and `token_fees_owed_*` alone understates the total — the accrued-since- +checkpoint part needs fee-growth math against the pool and the tick range. + +So this needs a live pancakeswap-sol close to fix correctly, and the test wallet holds no +position on that connector. Writing the arithmetic blind would produce a plausible non-zero, +which is harder to notice as wrong than the visible zero that is there now. + +**Same connector, same shape:** `pancakeswap-sol/clmm-routes/openPosition.ts` reports +`positionRent: 0` beside `Math.abs(change)`, so its rent is counted as deposited liquidity +*and* reported as zero — GW-20's defect, uncorrected here. + +**Not yet observed live** — read from the source rather than from a response. The related +`collect_fees` route on the same connector does report real amounts; only `closePosition` +flattens them. + +--- + +## GW-23 — money is typed as JSON `number`, so exact decimals do not survive the wire +**Status: open.** Seen repeatedly across 2026-08-19/20 mainnet runs. Cosmetic at the +amounts tested; the reason to fix it is that the failure grows with the number, and one +instance of it was a real bug already. + +Every monetary field is `Type.Number({ format: 'decimal' })` — **181 of them across +`src/`** — which the spec emits as `"type": "number"`. That is an IEEE 754 double, so a +value that is an exact decimal on-chain (an atomic integer over `10^decimals`) arrives as +the nearest representable double instead: + +``` +collect fees base: 4.2900000000000047E-7 (4.29e-7) + quote: 0.00003700000000250725 (0.000037) +swap record input_amount: 0.010000000000000002 (0.01) +``` + +The `format: 'decimal'` annotation is a hint no JSON parser acts on — it does not change +what is on the wire. + +**It defeats the consumer's Decimal.** hummingbot-api models these as `Decimal`, which +would be exact, but the value has already lost precision before pydantic sees it: + +```python +Decimal(str(0.00003700000000250725)) # 0.00003700000000250725 — noise preserved +Decimal('0.000037') # 0.000037 — if it were a string +``` + +**One instance of this was not cosmetic.** `page=2` came back from a numeric field as the +float `2.0` and went out on a query string as `"2.0"`, which is a different request from +`"2"`. Fixed in the clients with `_wire_str`, but that is a workaround at the edge — the +values were already floats by then. + +**Why it will not stay cosmetic.** Error is relative, so it scales with magnitude. At +0.01 SOL it is 1e-17 and invisible. On a token with 18 decimals, or a position worth +millions of base units, doubles run out of integer precision at 2^53 — a wei-denominated +amount above ~9e15 cannot round-trip at all. Fee and rent figures also get summed across +events, and the noise accumulates in whichever direction the rounding fell. + +**Fix:** carry money as strings — `Type.String({ format: 'decimal' })` — so the exact +decimal survives and every consumer's Decimal is exact. That is a breaking spec change +across 181 fields, so it wants doing in one pass with the generated models regenerated on +both sides; hummingbot-api already parses these into `Decimal`, which would then be +faithful rather than approximate. Keeping `number` and rounding at the edges is the +cheaper option, but it puts the correctness in every consumer instead of in the wire. + +--- + +## GW-12 — three ways a caller's intent is dropped without an error +**Status: open.** None of these returns a wrong answer; each accepts a request it could +have rejected, and acts on something other than what was asked. + +- **No component sets `additionalProperties: false`** — 0 of 80. `slippagePc: 5` on an + execute-swap is dropped and the trade goes out at the connector's configured slippage. + This is the exact failure hummingbot-api wrote `test_every_kwarg_is_a_field_of_the_model_it_names` + to catch on its own side, because pydantic drops unknown keywords the same way. +- **`x-connectors` is documentation, not validation.** `AmmCreatePoolRequest` carries both + `configAddress` (meteora) and `ammConfigIndex` (raydium); passing the wrong one creates a + pool with connector defaults rather than erroring. 21 fields across the spec are marked + this way and none is enforced. +- **Writes default their connector.** `POST /trading/clmm/add` with only `positionAddress` + gets `meteora`, `solana-mainnet-beta` and the config wallet injected by AJV `useDefaults` + and runs. The first connector in the registry is a strange venue to pick for a position + whose venue the caller did not name. + +**Fix, if wanted:** `additionalProperties: false` on the trading request schemas is the +one with real blast radius — it turns today's silently-ignored field into a 400, which is +the point, but any caller sending an extra key starts failing. Enforcing `x-connectors` is +contained: one check against the field's own extension in `resolveChainNetwork`'s +neighbourhood. Dropping the `connector` default from the write routes costs the Swagger +prefill, which is what it was for. + +--- + +## GW-14 — the spec names its types but not its operations or its errors +**Status: open.** The half of the generated-client contract GW-8/9/10 did not reach. + +**No operation has an `operationId`** — 0 of 58. That is the method name in a generated +client, so every generator synthesizes one from path and method, and every path change +renames the method. It is the same instability GW-9 fixed for models, still live for calls. + +**Three of 58 operations declare any non-2xx response** (`POST /pools/`, +`DELETE /pools/{address}`, `GET /pools/{tradingPair}`). A generated client therefore has no +error model at all, though `{statusCode, error, message, code?}` is the envelope every +route actually returns and the `code` is what callers branch on. + +Also undocumented: `GET /` and `POST /restart` are registered routes that `hideUntagged` +keeps out of the spec, and the ethereum-only routes are tagged `/chain/ethereum` where +everything else is `/chains`, which puts them in a separate class in a generated client. + +--- + +## GW-15 — response component names were never unified +**Status: open.** + +The request side got `Amm`/`Clmm` prefixes uniformly. The response side did not, so the +unprefixed name is the CLMM one and a reader has to know that: + +| CLMM route answers with | its AMM twin answers with | +|---|---| +| `PoolInfo` | `AmmPoolInfo` | +| `PositionInfo` | `AmmPositionInfo` | +| `AddLiquidityResponse` | `AmmAddLiquidityResponse` | +| `OpenPositionResponse` | `AmmOpenPositionResponse` | +| `QuotePositionResponse` | `QuoteLiquidityResponse` | + +The last row is also a stale name: the route was renamed `quote-position` → `quote-liquidity` +in the refactor and its response component kept the old word. `/chains/ethereum/allowances` +and `/approve` answer with inline objects where every other chain route has a component. + +--- + +## GW-16 — leftovers the unification did not sweep +**Status: open.** Cosmetic individually; together they are the difference between a +unified API and one that mostly looks unified. + +- **36 dead schema exports** survive the deleted per-connector routes — + `MeteoraClmmQuoteSwapRequest`, `PancakeswapSolClmm*` (11 of them), the jupiter/okx/dflow/ + titan request trio each. None is referenced by any route. `24795ffbb` swept some of these; + these are what it missed. **30 tests across four files assert their shape**, which is a + contract test for an API that no longer exists. +- **Three addressing conventions**, two of them inside one router: `/pools/` takes + `chain`+`network`, `/pools/find` takes `chainNetwork`, `/chains/{chain}/*` takes a path + `chain` plus a query `network`. Trading is uniformly `chainNetwork`. +- **Three `parseChainNetwork` implementations** with three validation levels: the one in + `src/trading/common.ts` rejects a value with no hyphen, `ConfigManagerV2`'s accepts + anything, and `src/pools/routes/findPools.ts:110` hand-rolls the split inline. +- **The registry covers swaps only.** Its header says a connector is one entry and the + routes are pure dispatch; that holds for `quoteSwap`/`executeSwap`/`fetchPools`, while 20 + route files still carry their own `switch (connector)` for every liquidity operation. + Adding a connector means editing all of them. +- **`/trading/router/execute-quote` has no caller.** `RouterExecuteQuoteRequest` is the one + generated request model hummingbot-api never constructs, so the quote-then-execute flow + that `quoteId` exists for is unused and every execute re-quotes. + +--- + +## GW-25 — a narrow in-range CLMM close fails on slippage, and no retry layer widens it +**Status: open.** Found live 2026-08-20 closing Orca positions. The mechanism is +established; the **cause is not confirmed** — see "What is not proven" below before acting +on it. + +### The case + +Three Orca SOL-USDC positions, opened minutes apart in the same pool, differing only in +where the range sat relative to spot. Closing them: + +| position | range vs spot | in range at close | slippage | result | +|---|---|---|---|---| +| `CzUtGJG8…` | below | no | 1% (default) | closed | +| `sWXmj6vg…` | above | no | 1% (default) | closed | +| `2PWGc9j7…` attempt 1 | across | **yes** | 1% | **failed in simulation** | +| `2PWGc9j7…` attempt 2 | across | **yes** | 1% | **landed on-chain, reverted** | +| `2PWGc9j7…` attempt 3 | across | no (drifted out) | 5% | closed | + +The failing position was 1% wide (85.6850–86.5808) and sitting 0.13% below its upper bound +when the closes were attempted. The error both times: + +``` +custom program error: 0x1782 // 6018 TokenMinSubceeded +Did not meet the minimum token amount for the liquidity withdrawal. +``` + +Gateway recognises it — `solana-error-parser.ts:97` is where that message comes from. + +### Two failure stages, one of which costs money + +The two attempts failed at **different points**, which matters more than the failure itself: + +``` +attempt 1 Transaction simulation failed — never submitted, no gas +attempt 2 landed on-chain but failed — slot 440494812, fee 0.000011772 SOL + InstructionError [1, {Custom: 6018}] +``` + +A close that clears simulation can still revert by the time it lands. So **retrying is not +free**: every attempt that gets past simulation before the price moves again pays a +transaction fee for a reverted transaction. + +### Why an in-range narrow position is the sensitive case + +A CLMM position's composition is fixed while it is out of range — it holds one token and +price movement cannot change the amount. The withdrawal minimums are then exact and cannot +be subceeded, which is why both one-sided closes above succeeded first time at the default +tolerance. + +In range, composition varies continuously with price, and the closer spot is to a bound the +faster it varies. This position went from `0.009533 SOL / 0.903469 USDC` at open to +`0.002486 / 1.511704` in nine minutes — the pool selling its base as spot rose through a +range only 1% wide. Between computing the withdrawal minimums and the transaction landing, +the amounts had moved past a 1% tolerance. + +### What is not proven + +**The tolerance hypothesis is untested.** Attempt 3 used 5% *and* the position had drifted +out of range by then, so its success has two candidate explanations and the experiment +cannot separate them. Every close that has ever succeeded here was out of range; both +failures were in range. Tolerance was never isolated. + +The discriminating experiment is a **narrow, in-range** position closed at a high +tolerance, which needs a fresh position and has to run before the position drifts out: + +``` +test_orca_clmm.py open-across # 1% wide, straddling spot +# then immediately, with slippage_pct=5, while `info` still reports [in range] +``` + +If that closes, tolerance is the cause and the recommendation below applies. If it fails +at 5% too, the cause is elsewhere and the retry logic should not be changed on this +evidence. + +### The retry layers, and what they do about it + +§3.1 of `docs/retry-architecture.md` specifies retry in two places. One exists: + +- **Connector fast path — not implemented.** `closePosition.ts` has no re-quote-and-resubmit; + its only retry is the confirmation re-fetch at line 54. The route returns a 400. Retry + logic exists in the router connectors (jupiter, okx, dflow) but not on the LP close path. + For a caller that is not an executor — `manage_clmm`, the orphan-recovery path — this + means the caller retries by hand. A convenience gap rather than a dead end: calling again + is what a human does, and it is what produced attempts 2 and 3 above. + +- **Executor paced re-entry — implemented, and correct for the failure mode it was built + for.** `lp_executor.py` counts attempts, arms an exponential backoff capped at 30s, + stays in `CLOSING`, and rebuilds with fresh state each time (`:194`, `:804`, `:808`). + `max_retries` defaults to 10, after which `_max_retries_reached` requires intervention. + +**The gap is that neither layer widens the tolerance.** `lp_executor.py:938` is explicit: + +```python +# No slippage_pct: omitted, the connector-configured slippagePct applies +``` + +Every one of the ten attempts re-quotes at the same tolerance. That is the right design for +a *stale quote* — get a fresh one and the problem is gone. It does nothing for a tolerance +that is too tight for the position's sensitivity: the fresh quote is just as tight as the +last one. If the hypothesis above holds, an executor-managed position in this state burns +its whole retry budget failing identically, pays a fee on each attempt that clears +simulation, and lands in "requires intervention" for a position one wider close would have +shut. + +### Recommendation for lp_executor + +Widen progressively across the existing retry budget rather than repeating the same +request. The backoff loop is already the right place; only the request changes. + +- **Pass `slippage_pct` explicitly on close, escalating with the attempt count** — the + connector-configured value on attempt 0, then a bounded ramp (e.g. ×1.5 per attempt, + capped at something the operator sets). The parameter already exists on the request and + is currently omitted, so this is a value to supply rather than a mechanism to build. +- **Cap it, and make the cap configuration rather than a constant.** Tolerance on a close + is not the same risk as on a swap: the intent is "remove whatever is in this position", + and the position is being exited regardless, so the exposure is to the withdrawal split + rather than to a price. It still bounds how much the closer will accept losing, so it + belongs in the executor config beside `max_retries`. +- **Distinguish the two failure stages in the retry accounting.** A simulation failure + costs nothing and can be retried freely; a landed-and-reverted one costs a fee. Counting + them the same way either spends the budget too fast on free failures or pays too many + fees on expensive ones. `throwIfLandedWithError` already separates them at the connector. +- **Consider out-of-range as a terminal-ish state for close purposes.** A position that has + drifted out of range will close at any tolerance, because its composition is frozen. If + the retry loop knows the position is out of range it can stop widening — and conversely, + a position still in range after several failures is the case that needs the widest + attempt. + +Whether the connector fast path is also worth adding is a separate question. It would save +the executor a tick, but the executor loop already covers the managed path and a widening +ramp there addresses the same failure with one implementation instead of two. + + +--- + +## GW-3 — OKX router has no API credentials +**Status: needs a decision. The error is now legible; the credentials are not populated.** + +`conf/connectors/okx.yml` still has `apiKey`, `secretKey` and `passphrase` empty, so every +quote through OKX fails. It was the one failure in an otherwise clean 36/37 read sweep; +jupiter, dflow and titan all quoted fine. + +**Changed:** the guard in `okx.ts:56` threw a plain `Error`, which reached callers as a +**500** — "Gateway broke, try again" for a condition no retry can fix. It now throws +`httpErrors.badRequest` with the same message. OKX is advertised in `/config/connectors`, +so anything enumerating providers hits this. + +**Still open, and yours to decide:** populate the three keys, or drop OKX from the +advertised connector list. Leaving it advertised-but-unconfigured is the one state that +misleads a caller enumerating providers. + +### What creating a key involves (researched 2026-08-20) + +Self-serve and free. Create an OKX account, verify email and phone, create a project (max 3 +per account), then create an API key inside it (max 3 per project) choosing a passphrase. +The secret key is shown only at creation and the passphrase is unrecoverable. Full steps +are in `src/connectors/okx/README.md`. + +Three things make it less attractive than "free and self-serve" suggests: + +- **The trial ceiling is 1 request/second**, raisable to 5 on review, for 60 days. That is + the binding constraint, not the expiry — a bot sweeping quotes across connectors exceeds + 1 RPS by itself. +- **Continuing past 60 days requires KYC** in the developer portal, which upgrades the + account to the Start-up tier. No per-call charge there, but a partner taking a fee on + swaps enters a revenue share where OKX keeps 20% of it. +- **A fifth header may be missing.** OKX's own client library sends `OK-ACCESS-PROJECT` + with the project ID; `okx.ts:107` sends only the four signed headers and `okx.config.ts` + has no field for a project ID. That library targets v5 while this connector calls v6, + whose quote reference lists only four — so this may be fine, but it cannot be tested + without credentials. If signed requests 401 once keys are populated, add the project ID + before investigating anything else. + +**Recommendation:** drop OKX from the advertised list unless its routing is specifically +wanted. Jupiter, dflow and titan all quoted cleanly in the read sweep, and a connector +capped at 1 RPS for 60 days and gated on KYC after that is not something to build on. +Creating a key to try it costs little; depending on it does. + +--- + +## Fixed — the record + +One line each. The full write-ups are in git history; what is kept here is what the issue +was, what closed it, and where. + +- **GW-0 — the `poolAddress` pin survived the refactor.** No action. It briefly looked lost + when `src/trading/swap/{quote,execute}.ts` were deleted; the rejection had moved to + `src/trading/common.ts` and the test to `test/trading/pool-swap/pool-address-pin.test.ts`, + extended to cover the router surface having no `poolAddress` parameter at all. +- **GW-1 — Meteora `quote-liquidity` priced the range midpoint.** The paired amount came + from the arithmetic mean of the requested range with no reference to the pool's active + bin. Re-implemented against the active bin after the first fix was lost in the refactor. +- **GW-2 — Raydium's AMM reported `feePct` as a fraction.** `0.0025` for a pool charging + 0.25%, where every other connector reports a percent. Scaled at `raydium.ts:326`. +- **GW-4 — native-SOL amounts were inflated by the transaction fee.** The wallet delta on a + native-SOL trade is the amount *plus* the fee, and `amountIn` reported the whole thing, so + the recorded price was wrong. `extractBalanceChangesAndFee` now nets the fee out of the + native side and reports it separately. +- **GW-5 — the execute response carried no `poolAddress`.** A settled fill could not be + attributed to a venue without refetching the transaction. The pool-scoped routes stamp it + on the confirmed `data`; the router leaves it unset, having no single pool. +- **GW-6 — an AMM add never returned the position it created.** Gateway generated the + position NFT, logged the address, and discarded it, so the caller who had just paid to + open a position could only recover it by re-listing and diffing. Now returned. +- **GW-7 — three sites double-counted the fee once GW-4 landed.** GW-4 changed the contract + of `extractBalanceChangesAndFee`; three callers kept applying their own correction. All + three dropped it. +- **GW-8 — nested `data` schemas were named but never registered.** The 16 confirmed- + transaction `data` objects were rewritten to `$ref`s pointing at components nobody + defined, so the spec resolved nowhere for exactly the fields that describe a settled trade. + `$id` collection now recurses through an already-collected schema. +- **GW-9 — request bodies were declared inline, so they could not be generated.** 24 of 28 + were anonymous objects in the route file, and the `$id`'d shapes in `src/schemas` were + pre-refactor bases carrying `network` and neither `connector` nor `chainNetwork` — wrong + the same way for every route. Each route's request const now carries the `$id`. +- **GW-10 — the reads published the wrong shape under the right name.** The GETs had no + component of their own, so names a client reaches for were held by shapes no route serves. + The `$id`s moved off the stale bases onto each route's querystring; all 12 trading GETs + publish a component matching their query exactly. +- **GW-11 — the chain half of `chainNetwork` was decorative on the liquidity routes.** + Fifteen routes read only the network half and dispatched on connector alone, so + `ethereum-mainnet` ran a Solana connector and a chain that exists nowhere ran anyway — on + a write, submitting a transaction. `chainNetworkField` gained an enum of the configured + chain-networks, and `resolveChainNetwork` checks the connector against the chain. + gateway `3d9e7d8e9` +- **GW-13 — the spec guard passed on regressions it claimed to catch.** Its shape matching + could not tell twins apart, and reading the committed spec never caught drift despite + saying so. CI regenerates and diffs; each `/trading` GET is pinned by component name and + then by shape. gateway `db6da4d75` +- **GW-17 — `baseTokenAmountAdded` was a signed wallet delta on three Raydium sites.** A + deposit was recorded negative, so summing the event table netted a round trip on one + connector and double-counted it on every other. The CLMM open also counted position rent + as liquidity — GW-20 on a second connector. gateway `d6e444f74` +- **GW-19 — a hyphen in a token symbol made its pair unquotable.** `split("-")` assumed no + symbol contains one, which chain-learned symbols do (`DOGE-1-SOL`). One helper splits from + the right and names the pair it rejects; eight call sites. hummingbot-api `979ff40` +- **GW-20 — a DAMM v2 open recorded the position rent as deposited liquidity.** The stored + position read 2.86× its real size and fabricated a ~186% loss on a round trip. + gateway `e3eb7b14f`, hummingbot-api `ad7c516`. **That second commit was itself wrong**: it + added the two rent columns to `GatewayCLMMPosition` while using them from both + repositories, which took `POST /gateway/amm/positions/search` down with a 500 and silently + dropped every AMM position booking. Fixed in hummingbot-api `55cf09e`, with the columns + added to the AMM model, migrations for both tables, and a structural test that every + attribute those methods touch is a real column. +- **GW-21 — nothing downstream could close an AMM position, so the rent was stranded.** + Fixed by collapsing the routes rather than wiring a second one. gateway `74a1ee512` +- **GW-22 — `position_info` answered about every position but the one it was given.** + `position_address` was declared, accepted by pydantic, and dropped by the handler. + condor `51300d7` +- **GW-24 — the committed spec carried a real wallet address and a local port.** The + `walletAddress` default came from the generating machine's config, 21 times over, and was + vendored into hummingbot-api and its generated models; `servers[0].url` carried a local + port. The generator substitutes the template placeholders, which is also what made GW-13's + drift check possible. gateway `db6da4d75` + +--- + +## What is not done + +- **GW-3's credentials** — the only item needing a decision. +- **Mainnet coverage as of 2026-08-19.** Run and confirmed: all three swap types + (router/clmm/amm), the full CLMM lifecycle on Meteora (open → add → remove → close), the + Raydium AMM round trip (add → remove) which surfaced GW-17, and a Meteora DAMM v2 open + which surfaced GW-20. Orca CLMM and the rest of the DAMM v2 lifecycle have scripts + (`condor/scripts_lp_test/test_orca_clmm.py`, `test_meteora_amm.py`) but are unrun. Also + unrun: fee collection against a position that has any, pool creation, and + `manage_amm(create_pool)`, which no test step exercises at all. The "verify" notes on the fixed issues above remain outstanding except + where a section says otherwise. +- **The seven open issues.** Six of them — GW-12, GW-14, GW-15, GW-16, GW-23 and GW-3 — + are not wrong answers: they are ways a wrong request is accepted quietly, or a right one + is described badly, or a decision nobody has taken. **GW-18 is the exception** and the one + to take first: it is a stored number that is wrong, in the same category as GW-17 and + GW-20, and it is blocked only on having a pancakeswap-sol position to close. +- **Connector-specific response fields are gone from HTTP** — orca's `sqrtPrice`/`tvlUsdc`, + 0x's `gasEstimate`, jupiter's `quoteResponse`. Deleting `/connectors/*` removed the only + surface that exposed them. If any are wanted back, the fix is extending the unified + response schemas, not restoring the routes. diff --git a/agents/adaptive_grid_trader/AGENT.md b/agents/adaptive_grid_trader/AGENT.md index e7e264b2..b5a1c6eb 100644 --- a/agents/adaptive_grid_trader/AGENT.md +++ b/agents/adaptive_grid_trader/AGENT.md @@ -2,7 +2,7 @@ name: Adaptive Grid Trader description: Expert in multi-timeframe adaptive grid trading with safety-first order sizing, a configurable untraded reserve, and strict risk management -agent_key: claude-acp:opus +agent_key: claude-acp:sonnet tools: - get_market_data - get_portfolio_overview diff --git a/agents/adaptive_grid_trader/routines/kalman_grid_operator.py b/agents/adaptive_grid_trader/routines/kalman_grid_operator.py new file mode 100644 index 00000000..8f0edc22 --- /dev/null +++ b/agents/adaptive_grid_trader/routines/kalman_grid_operator.py @@ -0,0 +1,374 @@ + +import asyncio +import time +from pydantic import BaseModel, Field +from telegram.ext import ContextTypes +from config_manager import get_client +from condor.reports import LiveReport +import numpy as np +import logging + +logger = logging.getLogger(__name__) + +CONTINUOUS = True +CATEGORY = "Analysis" + + +class Config(BaseModel): + """Kalman adaptive grid operator — 1m regime check every minute, tunes grid on bitget_perpetual.""" + connector_name: str = Field(default="bitget_perpetual", description="Exchange connector") + trading_pair: str = Field(default="BTC-USDT", description="Trading pair") + budget_usdt: float = Field(default=100.0, description="Total USDT budget") + reserve_pct: float = Field(default=0.10, description="Fraction held back (never traded)") + max_leverage: int = Field(default=5, description="Max leverage") + max_loss_pct: float = Field(default=0.10, description="Max loss per grid as fraction of budget") + min_order_size: float = Field(default=5.0, description="Min order size in USDT") + interval_sec: int = Field(default=60, description="Tick interval in seconds") + lookback_candles: int = Field(default=60, description="1m candles (60 = last 1 hour)") + q_level: float = Field(default=100.0, description="Kalman process noise: level variance") + q_slope: float = Field(default=1.0, description="Kalman process noise: slope variance") + r_obs: float = Field(default=40.0, description="Kalman observation noise variance") + snr_trend_threshold: float = Field(default=0.3, description="SNR >= this → deploy directional grid") + target_grid_hours: float = Field(default=8.0, description="Target grid lifetime (hours) for D sizing") + retune_d_pct: float = Field(default=0.20, description="Retune grid if Kalman D shifts by this fraction") + min_grid_age_min: int = Field(default=180, description="Min grid age (min) before directional flip") + profit_take_pct: float = Field(default=0.02, description="Take profit at this fraction of budget ($2 on $100)") + stale_ticks: int = Field(default=10, description="Recycle grid if fills stagnant for this many ticks") + + +# ── Kalman filter ───────────────────────────────────────────────────────────── + +def _kalman_filter(prices, q_level, q_slope, r_obs): + """Local linear trend Kalman filter. Returns (slopes, innovations).""" + F = np.array([[1.0, 1.0], [0.0, 1.0]]) + H = np.array([[1.0, 0.0]]) + Q = np.diag([q_level, q_slope]) + R = np.array([[r_obs]]) + x = np.array([prices[0], 0.0]) + P = np.eye(2) * 1e6 + slopes, innovations = [], [] + for price in prices: + x_pred = F @ x + P_pred = F @ P @ F.T + Q + inn = price - float((H @ x_pred)[0]) + S = float((H @ P_pred @ H.T + R)[0, 0]) + K = (P_pred @ H.T / S).flatten() + x = x_pred + K * inn + P = (np.eye(2) - np.outer(K, H)) @ P_pred + slopes.append(float(x[1])) + innovations.append(float(inn)) + return np.array(slopes), np.array(innovations) + + +def _get_signal(slopes, innovations, prices, config): + """Return (regime, profile, snr, slope_pct, sigma_inn, grid_D, current_price).""" + n = len(prices) + window = min(24, max(n // 6, 4)) + recent_slope = slopes[-1] + current_price = float(prices[-1]) + rms_inn = float(np.sqrt(np.mean(innovations[-window:] ** 2))) + sigma_inn = max(rms_inn, 1.0) + slope_pct = recent_slope / current_price * 100 + snr = abs(recent_slope) / sigma_inn + # D scales so grid width is the same regardless of candle timeframe (1m candles here) + grid_D = sigma_inn * float(np.sqrt(config.target_grid_hours * 60)) + if n < 30: + return "UNCERTAIN", "HOLD", snr, slope_pct, sigma_inn, grid_D, current_price + if snr >= config.snr_trend_threshold: + regime = "TRENDING_UP" if recent_slope > 0 else "TRENDING_DOWN" + profile = "LONG" if recent_slope > 0 else "SHORT" + else: + regime = "RANGING/UNCERTAIN" + profile = "HOLD" + return regime, profile, snr, slope_pct, sigma_inn, grid_D, current_price + + +# ── Grid config builder ─────────────────────────────────────────────────────── + +def _grid_config(direction, price, grid_D, config): + trade_budget = config.budget_usdt * (1 - config.reserve_pct) + if direction == "LONG": + start = round(price - grid_D, 1) + end = round(price + 3 * grid_D, 1) + limit = round(price - 1.5 * grid_D, 1) + side = "BUY" + else: + start = round(price - 3 * grid_D, 1) + end = round(price + grid_D, 1) + limit = round(price + 1.5 * grid_D, 1) + side = "SELL" + n_levels = max(2, min(20, int(trade_budget / config.min_order_size))) + return { + "type": "grid_executor", + "timestamp": time.time(), + "connector_name": config.connector_name, + "trading_pair": config.trading_pair, + "start_price": start, + "end_price": end, + "limit_price": limit, + "total_amount_quote": trade_budget, + "n_levels": n_levels, + "min_spread_between_orders": 0.001, + "min_order_amount_quote": config.min_order_size, + "leverage": config.max_leverage, + "side": side, + "time_limit": 86400, + "keep_position": False, + "triple_barrier_config": { + "take_profit": 0.003, + "stop_loss": 0.02, + "stop_loss_order_type": "MARKET", + }, + } + + +# ── Executor helpers ────────────────────────────────────────────────────────── + +async def _teardown(client, executor_id, log, ts): + try: + await client.executors.stop_executor(executor_id) + log.append(f"{ts} TEARDOWN {executor_id[:8]} OK") + except Exception as e: + log.append(f"{ts} WARN stop failed: {e}") + + +async def _deploy(client, direction, price, grid_D, config, log, ts): + gcfg = _grid_config(direction, price, grid_D, config) + try: + result = await client.executors.create_executor(gcfg) + eid = str(result.get("id") or result.get("executor_id", "")) + log.append( + f"{ts} DEPLOY {direction} {eid[:8]} " + f"${gcfg['start_price']:.0f}–${gcfg['end_price']:.0f} " + f"lim=${gcfg['limit_price']:.0f} D=${grid_D:.0f}" + ) + return eid, grid_D + except Exception as e: + log.append(f"{ts} ERROR deploy: {e}") + return None, None + + +# ── Main loop ───────────────────────────────────────────────────────────────── + +async def run(config: Config, context: ContextTypes.DEFAULT_TYPE) -> str: + chat_id = context._chat_id + await context.bot.send_message(chat_id=chat_id, text="Kalman Grid Operator started") + + # Persistent state + executor_id = None + direction = None + grid_D_deployed = None + deployed_at = None + pnl_history = [] + fills_history = [] + tick_count = 0 + log = [] + + report = LiveReport( + "Kalman Grid Operator", + source_name="kalman_grid_operator", + tags=["trading", "kalman", "adaptive-grid-trader", "live"], + auto_refresh_seconds=60, + ) + + try: + while True: + try: + tick_count += 1 + ts = time.strftime("%H:%M:%S") + client = await get_client(chat_id, context=context) + if not client: + await asyncio.sleep(config.interval_sec) + continue + + # ── 1. Kalman signal ────────────────────────────────────── + raw = await client.market_data.get_candles( + config.connector_name, config.trading_pair, + interval="1m", max_records=config.lookback_candles, + ) + records = raw if isinstance(raw, list) else raw.get("data", raw.get("candles", [])) + closes = [] + for r in (records or []): + try: + closes.append(float(r["close"])) + except (KeyError, TypeError, ValueError): + continue + + if len(closes) < 20: + log.append(f"{ts} SKIP: only {len(closes)} candles") + await asyncio.sleep(config.interval_sec) + continue + + prices = np.array(closes) + slopes, innovations = _kalman_filter( + prices, config.q_level, config.q_slope, config.r_obs + ) + regime, profile, snr, slope_pct, sigma_inn, grid_D, current_price = _get_signal( + slopes, innovations, prices, config + ) + + # ── 2. Executor state & action decision ─────────────────── + pnl = 0.0 + fills = 0.0 + grid_age_min = 0 + action = "keep" + action_reason = f"snr={snr:.2f}" + new_direction = direction + + if executor_id is not None: + execs = await client.executors.search_executors( + controller_ids=[], status="active", limit=50 + ) + our_exec = next( + (e for e in (execs or []) + if str(e.get("id") or e.get("executor_id", "")) == executor_id), + None, + ) + + if our_exec is None: + # Grid ended on its own — reset and redeploy + log.append(f"{ts} Grid {executor_id[:8]} gone") + executor_id = grid_D_deployed = deployed_at = None + pnl_history.clear() + fills_history.clear() + new_direction = profile if profile in ("LONG", "SHORT") else direction + action = "deploy" + action_reason = "grid_died" + else: + pnl = float(our_exec.get("net_pnl_quote", 0)) + fills = float(our_exec.get("filled_amount_quote", 0)) + grid_age_min = int((time.time() - deployed_at) / 60) if deployed_at else 0 + pnl_history.append(pnl) + fills_history.append(fills) + if len(pnl_history) > 20: + pnl_history.pop(0) + if len(fills_history) > config.stale_ticks + 2: + fills_history.pop(0) + + profit_target = config.budget_usdt * config.profit_take_pct + + # Priority: stale → profit → D-drift → flip → keep + if (len(fills_history) >= config.stale_ticks and + len(set(round(f, 2) for f in fills_history[-config.stale_ticks:])) == 1): + action = "retune" + action_reason = f"stale {config.stale_ticks}t" + new_direction = direction # same direction, fresh range + + elif pnl >= profit_target: + action = "retune" + action_reason = f"profit_take ${pnl:.2f}" + new_direction = profile if profile in ("LONG", "SHORT") else None + + elif (grid_D_deployed and + abs(grid_D - grid_D_deployed) / grid_D_deployed > config.retune_d_pct): + d_shift = abs(grid_D - grid_D_deployed) / grid_D_deployed + action = "retune" + action_reason = f"D_drift {d_shift:.0%}" + new_direction = direction # same direction, updated range + + elif (profile not in ("HOLD", direction) and + profile in ("LONG", "SHORT") and + grid_age_min >= config.min_grid_age_min): + action = "flip" + action_reason = f"→{profile} age={grid_age_min}m" + new_direction = profile + + else: + action = "keep" + action_reason = f"regime={regime} snr={snr:.2f}" + + else: + # No grid running + if profile in ("LONG", "SHORT"): + action = "deploy" + action_reason = f"regime={regime} snr={snr:.2f}" + new_direction = profile + else: + action = "hold" + action_reason = f"regime={regime} snr={snr:.2f}" + + # ── 3. Execute ──────────────────────────────────────────── + if action in ("retune", "flip"): + await _teardown(client, executor_id, log, ts) + executor_id = grid_D_deployed = deployed_at = None + pnl = fills = 0.0 + pnl_history.clear() + fills_history.clear() + direction = new_direction + if direction in ("LONG", "SHORT"): + action = "deploy" + else: + action = "hold" + + if action == "deploy" and new_direction in ("LONG", "SHORT"): + direction = new_direction + trade_budget = config.budget_usdt * (1 - config.reserve_pct) + if trade_budget < config.min_order_size * 2: + log.append(f"{ts} HOLD: budget too small") + action = "hold" + else: + eid, D_dep = await _deploy( + client, direction, current_price, grid_D, config, log, ts + ) + if eid: + executor_id = eid + grid_D_deployed = D_dep + deployed_at = time.time() + elif action == "deploy": + action = "hold" + direction = None + log.append(f"{ts} HOLD: no signal for redeploy") + + # ── 4. Log & LiveReport ─────────────────────────────────── + log.append( + f"{ts} [{action.upper()}] {regime} SNR={snr:.2f} " + f"D=${grid_D:.0f} pnl=${pnl:+.2f} fills=${fills:.2f}" + ) + if len(log) > 60: + log[:] = log[-60:] + + report.clear() + report.builder.manual_order() + + report.builder.section("01 / KALMAN SIGNAL", "1m Kalman regime — updated every tick") + report.builder.kpi("Regime", regime) + report.builder.kpi("Profile", profile) + report.builder.kpi("Price", f"${current_price:,.2f}") + report.builder.kpi("Slope", f"{slope_pct:+.5f}%/m") + report.builder.kpi("σ Innovation", f"${sigma_inn:.2f}") + report.builder.kpi("SNR", f"{snr:.3f}") + report.builder.kpi("Grid D", f"${grid_D:.2f}") + + report.builder.section("02 / GRID STATE") + report.builder.kpi("Status", "RUNNING" if executor_id else "FLAT") + report.builder.kpi("Direction", direction or "—") + report.builder.kpi("Age", f"{grid_age_min}m" if executor_id else "—") + report.builder.kpi("Unrealized PnL", f"${pnl:+.2f}" if executor_id else "—") + report.builder.kpi("Filled", f"${fills:.2f}" if executor_id else "—") + report.builder.kpi("D Deployed", f"${grid_D_deployed:.2f}" if grid_D_deployed else "—") + report.builder.kpi("Action", f"{action} ({action_reason})") + report.builder.kpi("Tick #", str(tick_count)) + + report.builder.section("03 / LOG") + report.builder.markdown("\n".join(f"`{l}`" for l in log[-20:])) + + await report.update() + + except asyncio.CancelledError: + raise + except Exception as e: + logger.warning(f"Tick {tick_count} error: {e}") + + await asyncio.sleep(config.interval_sec) + + except asyncio.CancelledError: + if report.report_id is not None: + report.clear() + report.builder.auto_refresh(None) + report.builder.section("STOPPED", f"Final snapshot — {tick_count} ticks") + report.builder.kpi("Total Ticks", str(tick_count)) + report.builder.kpi("Direction", direction or "—") + report.builder.kpi("Grid", executor_id[:8] if executor_id else "FLAT") + report.builder.markdown("\n".join(f"`{l}`" for l in log[-20:])) + await report.update() + return f"Kalman Grid Operator stopped after {tick_count} ticks" diff --git a/agents/adaptive_grid_trader/routines/kalman_regime_check.py b/agents/adaptive_grid_trader/routines/kalman_regime_check.py new file mode 100644 index 00000000..543fd238 --- /dev/null +++ b/agents/adaptive_grid_trader/routines/kalman_regime_check.py @@ -0,0 +1,194 @@ + +from pydantic import BaseModel, Field +from telegram.ext import ContextTypes +from config_manager import get_client +from condor.reports import ReportBuilder +import numpy as np +import plotly.graph_objects as go +from plotly.subplots import make_subplots +import logging +from datetime import datetime, timezone + +logger = logging.getLogger(__name__) + +CATEGORY = "Analysis" + + +def _candle_minutes(interval: str) -> float: + """Parse '1m'→1, '1h'→60, '4h'→240, '1d'→1440.""" + if interval.endswith("m"): + return float(interval[:-1]) + elif interval.endswith("h"): + return float(interval[:-1]) * 60 + elif interval.endswith("d"): + return float(interval[:-1]) * 1440 + return 1.0 + + +class Config(BaseModel): + """Kalman filter regime detection — outputs regime signal and Kalman-sized grid params.""" + connector_name: str = Field(default="bitget_perpetual", description="Exchange connector") + trading_pair: str = Field(default="BTC-USDT", description="Trading pair") + candle_interval: str = Field(default="1m", description="Candle interval (1m, 5m, 1h, etc.)") + lookback_candles: int = Field(default=60, description="Candles to fetch (60 × 1m = last 1 hour)") + q_level: float = Field(default=100.0, description="Process noise: level variance") + q_slope: float = Field(default=1.0, description="Process noise: slope variance") + r_obs: float = Field(default=40.0, description="Observation noise variance") + snr_trend_threshold: float = Field(default=0.3, description="SNR >= this → TRENDING") + snr_range_threshold: float = Field(default=0.1, description="SNR <= this → RANGING") + target_grid_hours: float = Field(default=8.0, description="Target grid lifetime (hours) for D sizing") + + +async def run(config: Config, context: ContextTypes.DEFAULT_TYPE) -> str: + client = await get_client(context._chat_id, context=context) + if not client: + return "No server available" + + result = await client.market_data.get_candles( + config.connector_name, config.trading_pair, + interval=config.candle_interval, max_records=config.lookback_candles + ) + records = result if isinstance(result, list) else result.get("data", result.get("candles", [])) + if not records or len(records) < 20: + return f"Insufficient candle data: got {len(records) if records else 0} records" + + closes, timestamps = [], [] + for r in records: + try: + closes.append(float(r["close"])) + ts = r.get("timestamp", r.get("time", 0)) + if isinstance(ts, (int, float)) and ts > 0: + t = ts / 1000 if ts > 1e10 else ts + timestamps.append(datetime.fromtimestamp(t, tz=timezone.utc).strftime("%m-%d %H:%M")) + else: + timestamps.append(str(ts)) + except (KeyError, TypeError, ValueError): + continue + + if len(closes) < 20: + return f"Could not parse enough closes: got {len(closes)}" + + prices = np.array(closes) + n = len(prices) + x_axis = timestamps[:n] if len(timestamps) == n else list(range(n)) + + # Local Linear Trend Kalman Filter + F = np.array([[1.0, 1.0], [0.0, 1.0]]) + H = np.array([[1.0, 0.0]]) + Q = np.diag([config.q_level, config.q_slope]) + R = np.array([[config.r_obs]]) + x = np.array([prices[0], 0.0]) + P = np.eye(2) * 1e6 + + levels, slopes, innovations = [], [], [] + for price in prices: + x_pred = F @ x + P_pred = F @ P @ F.T + Q + inn = price - float((H @ x_pred)[0]) + S = float((H @ P_pred @ H.T + R)[0, 0]) + K = (P_pred @ H.T / S).flatten() + x = x_pred + K * inn + P = (np.eye(2) - np.outer(K, H)) @ P_pred + levels.append(float(x[0])) + slopes.append(float(x[1])) + innovations.append(float(inn)) + + levels = np.array(levels) + slopes = np.array(slopes) + innovations = np.array(innovations) + + window = min(24, max(n // 6, 4)) + recent_slope = slopes[-1] + recent_price = prices[-1] + rms_inn = float(np.sqrt(np.mean(innovations[-window:] ** 2))) + sigma_inn = max(rms_inn, 1.0) + slope_pct = recent_slope / recent_price * 100 + snr = abs(recent_slope) / sigma_inn + + # D: scale by candle duration so grid width is timeframe-agnostic + candle_min = _candle_minutes(config.candle_interval) + grid_D = sigma_inn * float(np.sqrt(config.target_grid_hours * 60 / candle_min)) + + if n < 30: + regime, profile = "UNCERTAIN", "HOLD" + elif snr >= config.snr_trend_threshold: + regime = "TRENDING_UP" if recent_slope > 0 else "TRENDING_DOWN" + profile = "LONG" if recent_slope > 0 else "SHORT" + elif snr <= config.snr_range_threshold: + regime, profile = "RANGING", "TWO_SIDED" + else: + regime, profile = "UNCERTAIN", "HOLD" + + if regime == "TRENDING_UP": + g_start = recent_price - grid_D + g_end = recent_price + 3 * grid_D + g_limit = recent_price - 1.5 * grid_D + elif regime == "TRENDING_DOWN": + g_start = recent_price - 3 * grid_D + g_end = recent_price + grid_D + g_limit = recent_price + 1.5 * grid_D + else: + g_start = recent_price - 1.5 * grid_D + g_end = recent_price + 1.5 * grid_D + g_limit = None + + fig = make_subplots( + rows=3, cols=1, shared_xaxes=True, + subplot_titles=[ + f"Price vs Kalman Level — {config.trading_pair}", + "Kalman Slope ($/candle)", + "Innovation ($)" + ], + row_heights=[0.5, 0.25, 0.25], + vertical_spacing=0.07, + ) + fig.add_trace(go.Scatter(x=x_axis, y=prices.tolist(), name="Close", + line=dict(color="#94a3b8", width=1)), row=1, col=1) + fig.add_trace(go.Scatter(x=x_axis, y=levels.tolist(), name="Kalman Level", + line=dict(color="#60a5fa", width=2)), row=1, col=1) + slope_colors = ["#22c55e" if s > 0 else "#ef4444" for s in slopes] + fig.add_trace(go.Bar(x=x_axis, y=slopes.tolist(), name="Slope", + marker_color=slope_colors, showlegend=False), row=2, col=1) + fig.add_hline(y=0, line_dash="dash", line_color="gray", line_width=1, row=2, col=1) + inn_colors = ["#f97316" if abs(i) > 2 * sigma_inn else "#64748b" for i in innovations] + fig.add_trace(go.Bar(x=x_axis, y=innovations.tolist(), name="Innovation", + marker_color=inn_colors, showlegend=False), row=3, col=1) + fig.add_hline(y=sigma_inn, line_dash="dot", line_color="#22c55e", line_width=1, row=3, col=1) + fig.add_hline(y=-sigma_inn, line_dash="dot", line_color="#22c55e", line_width=1, row=3, col=1) + fig.update_layout( + height=700, template="plotly_dark", + title=f"Kalman Regime: {regime} | SNR={snr:.3f} | {config.candle_interval} × {n}", + legend=dict(orientation="h", yanchor="top", y=-0.15, xanchor="center", x=0.5), + ) + + builder = ReportBuilder("Kalman Regime Check") + builder.source("routine", "kalman_regime_check") + builder.tags(["analysis", "regime", "kalman", "adaptive-grid-trader"]) + + builder.section("01 / REGIME SIGNAL", "Kalman filter output and profile recommendation") + builder.kpi("Regime", regime) + builder.kpi("Profile", profile) + builder.kpi("Current Price", f"${recent_price:,.2f}") + builder.kpi("Kalman Slope", f"{slope_pct:+.5f}%/candle") + builder.kpi("Innovation RMS", f"${sigma_inn:,.2f}") + builder.kpi("SNR", f"{snr:.3f}") + builder.kpi("Candles Used", str(n)) + + builder.section("02 / GRID SIZING", "Kalman-derived grid parameters") + builder.kpi("Grid D", f"${grid_D:,.2f}") + builder.kpi("Grid Start", f"${g_start:,.2f}") + builder.kpi("Grid End", f"${g_end:,.2f}") + builder.kpi("Limit Price", f"${g_limit:,.2f}" if g_limit else "N/A (ranging/uncertain)") + + builder.section("03 / CHARTS", "Price, slope, and innovation over lookback window") + builder.plotly(fig) + + builder.manual_order() + await builder.save() + + return ( + f"Regime: {regime} → {profile}\n" + f"Price ${recent_price:,.2f} | Slope {slope_pct:+.5f}%/candle | SNR {snr:.3f}\n" + f"Grid D ${grid_D:,.2f} | Range ${g_start:,.2f}–${g_end:,.2f}" + + (f" | Limit ${g_limit:,.2f}" if g_limit else "") + ) diff --git a/agents/adaptive_grid_trader/strategies/kalman_grid_btc/strategy.md b/agents/adaptive_grid_trader/strategies/kalman_grid_btc/strategy.md new file mode 100644 index 00000000..47122026 --- /dev/null +++ b/agents/adaptive_grid_trader/strategies/kalman_grid_btc/strategy.md @@ -0,0 +1,106 @@ +--- +name: kalman_grid_btc +description: '' +agent_key: null +skills: [] +default_config: {} +default_trading_context: '' +created_by: 456181693 +created_at: '2026-08-13T03:14:12.657657+00:00' +--- + + +# Kalman Grid Strategy — BTC-USDT / bitget_perpetual + +## Envelope (fixed — never ask per tick) +- connector: bitget_perpetual +- pair: BTC-USDT +- budget: 100 USDT | reserve: 10% | trade_budget: $90 +- max_leverage: 5x | max_loss_pct: 10% ($10 max per grid) +- min_order_size: 5 USDT +- allowed_profiles: LONG, SHORT only (no TWO_SIDED) + +## Every tick + +### 1 — Kalman signal +``` +manage_routines(action="run", name="kalman_regime_check", config={ + "connector_name": "bitget_perpetual", + "trading_pair": "BTC-USDT", + "candle_interval": "1m", + "lookback_candles": 60 +}) +``` +Extract from result: regime, profile, snr, grid_D, grid_start, grid_end, limit_price. + +### 2 — Executor state +``` +manage_executors(action="list_executors") +``` +Find any active grid_executor for BTC-USDT on bitget_perpetual. Note: executor_id, net_pnl_quote, filled_amount_quote, created_timestamp. + +### 3 — Decide (first match wins) + +**No executor running:** +- profile LONG or SHORT → DEPLOY +- else → HOLD + +**Executor running:** +1. fills_amount_quote unchanged 10+ ticks → RETUNE (teardown + redeploy same direction) +2. net_pnl_quote ≥ $2.00 → PROFIT_TAKE (teardown + redeploy if signal still directional) +3. current grid_D differs >20% from deployed D → RETUNE (teardown + redeploy updated range) +4. profile flipped AND executor age ≥ 180 min → FLIP (teardown + deploy new direction) +5. else → KEEP + +### 4 — Act + +**DEPLOY grid:** +``` +manage_executors(action="create_executor", executor_config={ + "type": "grid_executor", + "connector_name": "bitget_perpetual", + "trading_pair": "BTC-USDT", + "start_price": , + "end_price": , + "limit_price": , + "total_amount_quote": 90, + "n_levels": 9, + "min_spread_between_orders": 0.001, + "min_order_amount_quote": 5, + "leverage": 5, + "side": "BUY" if LONG else "SELL", + "time_limit": 86400, + "keep_position": false, + "triple_barrier_config": { + "take_profit": 0.003, + "stop_loss": 0.02, + "stop_loss_order_type": "MARKET" + } +}) +``` + +**STOP grid:** +``` +manage_executors(action="stop_executor", executor_id=) +``` +Always verify flat (net position = 0) before redeploying. + +### 5 — Journal every tick +``` +trading_agent_journal_write(entries=[ + {"key": "regime", "value": }, + {"key": "snr", "value": }, + {"key": "grid_D", "value": }, + {"key": "profile", "value": }, + {"key": "action", "value": }, + {"key": "pnl", "value": }, + {"key": "fills", "value": } +]) +``` + +## Safety — abort and alert if: +- Available balance < $90 before deploy +- Worst-case loss at limit_price > $10 +- Liquidation price inside limit_price at 5x +- Position cannot be verified flat after teardown + diff --git a/agents/derive_options_trader/AGENT.md b/agents/derive_options_trader/AGENT.md new file mode 100644 index 00000000..837b4ae4 --- /dev/null +++ b/agents/derive_options_trader/AGENT.md @@ -0,0 +1,160 @@ +--- +name: Derive Options Trader +description: Directional perp trader on Derive (`derive_perpetual`) — reads Derive + options market positioning (25-delta risk reversal, put/call OI ratio, IV term + structure, net GEX) and takes LONG/SHORT/HOLD on SOL/USDC. Leverage enabled; + bounded risk. Tested on Derive mainnet only. +agent_key: claude-acp:sonnet +tools: +- manage_routines +- manage_executors +- get_portfolio_overview +- get_market_data +- search_history +- manage_memory +- manage_skill +- trading_agent_journal_write +when_to_consult: When the user wants a read on options-market positioning (risk + reversals, put/call OI, GEX) for crypto, or wants to deploy the Derive Options + Trader agent (options-driven perp positioning on Derive). +server_required: false +server_name: '' +created_by: 5587715073 +created_at: '2026-07-28T00:00:00.000000+00:00' +--- + +# Derive Options Trader + +You are **Derive Options Trader** — a **directional perpetual-futures trader on Derive** +(`derive_perpetual`) whose edge is **options market positioning**: what the options +market is *paying for*, not where price has been. Your core signal is live Derive +options data — risk reversals, open-interest skew, term structure, and dealer gamma — +captured by the `options_flow` routine. + +All strategies trade the same instrument: **SOL-USDC perpetuals on Derive**. Each +strategy runs on its own cadence and consumes the options read in its own way — the +`options_oracle_operator` trades it directly; the `smart_money_flow` strategy uses it +to confirm a cross-market capital-flow read. + +**Tagline:** *"Trade what the options market knows."* + +--- + +## Tested on Derive + +Execution uses the **Derive perpetual connector** (`derive_perpetual`) on mainnet, funded +with USDC. Routines produce *signals*; they never call an exchange API directly. The venue +is set in `default_trading_context` / the configured Hummingbot server, not in code. + +> **Status:** validated end-to-end on Derive mainnet (LONG `SOL-USDC` placed and closed, +> ~$0.02 fees). Other perpetual venues are not yet tested. + +--- + +## Core Signal — Options Market Positioning (`options_flow`) + +Pulls live Derive options data via the **Derive public API** (`https://api.lyra.finance`) +across all active expiries. No authentication required. + +### Derive Options API Reference + +``` +POST https://api.lyra.finance/public/get_tickers + { "currency": "SOL", "instrument_type": "option", "expired": false, "expiry_date": "YYYYMMDD" } + +POST https://api.lyra.finance/public/get_instruments + { "currency": "SOL", "instrument_type": "option", "expired": false } + +POST https://api.lyra.finance/public/get_ticker + { "instrument_name": "SOL-PERP" } +``` + +**Instrument naming:** `{CURRENCY}-{YYYYMMDD}-{STRIKE}-{C|P}` e.g. `SOL-20260828-80-C` + +**Ticker compact-key reference:** +| Key | Meaning | +|---|---| +| `option_pricing.d` | Delta | +| `option_pricing.g` | Gamma | +| `option_pricing.i` | Implied Volatility (annualized) | +| `option_pricing.v` | Vega | +| `stats.oi` | Open Interest (contracts) | +| `stats.v` | 24h Volume | +| `M` | Mark price (USDC) | +| `I` | Index price (USDC) | + +### Four Sub-Signals + +| Signal | Weight | Range | Bullish | Bearish | +|---|---|---|---|---| +| **25D Risk Reversal** | 50% | tanh(RR / 0.05) | Calls bid vs puts | Puts bid vs calls | +| **Put/Call OI Ratio** | 35% | tanh(log ratio × 1.5) | Call-heavy OI | Put-heavy OI | +| **ATM IV Term Structure** | 15% | −0.5 / 0 / +0.2 | Normal contango | Inverted (near > far) | +| **GEX Amplifier** | modifier | 0.75× or 1.25× | — | — | + +**25D Risk Reversal:** `IV(25Δ call) − IV(25Δ put)`. Positive = market pays up for calls += bullish. Near-term expiries weighted by 1/DTE so overnight options dominate. + +**Put/Call OI Ratio:** `log(put_OI / call_OI)`, OI-magnitude weighted across expiries. +Call-heavy open interest = institutional long positioning = bullish. + +**ATM IV Term Structure:** Compares near-expiry vs far-expiry ATM IV. +- Inverted (near > far by 5%+): `ts_score = −0.50` — near-term fear. +- Normal contango (far > near by 5%+): `ts_score = +0.20` — orderly, mild bullish. + +**Net GEX:** `Σ sign(type) × gamma × OI × spot² × 0.01` on the nearest liquid expiry. +- Positive GEX (dealers long gamma) → price gravity, range-bound → dampen composite 0.75×. +- Negative GEX (dealers short gamma) → momentum → amplify composite 1.25×. + +**Output:** `composite_score` (−1 to +1), `direction` (LONG / SHORT / HOLD), +`confidence` (LOW / MEDIUM / HIGH — count of sub-signals in agreement). + +**Act when:** `|composite_score| ≥ 0.40`. Below → HOLD. + +### Sizing by confidence + +| Confidence | Meaning | Size | Leverage | +|---|---|---|---| +| HIGH (3 signals agree) | Strong institutional consensus | 75% of `total_amount_quote` | up to 3× | +| MEDIUM (2 signals agree) | Partial consensus | 50% of `total_amount_quote` | 2× | +| LOW (≤1 signal in direction) | Noise | skip — HOLD | — | + +--- + +## Strategies + +| Strategy | Signal | Cadence | Instruments | +|---|---|---|---| +| `options_oracle_operator` | `options_flow` (pure options positioning) | 5 min | SOL-USDC, `derive_perpetual` | +| `smart_money_flow` | `onchain_flow` capital-flow read, confirmed against `options_flow` | 5 min | SOL-USDC, `derive_perpetual` | + +Both trade **SOL-USDC on `derive_perpetual`**. They can run concurrently — each holds at +most one position (`max_open_executors: 1` per strategy). The smart-money capital-flow +composite (cross-market regime + Solana on-chain pulse) lives entirely in the +`smart_money_flow` strategy playbook; at the agent level, options positioning is the +shared source of truth. + +--- + +## Risk Discipline (applies to all strategies) + +- Max 1 position per strategy; max 2× leverage unless confidence=HIGH and |score| ≥ 0.70 (then 3×). +- Never enter when confidence=LOW or |composite| < threshold. No forced trades. +- Hard stop always set inside `triple_barrier_config` — never rely solely on the Risk Engine. +- Max drawdown 8% of deployed capital per strategy (`max_drawdown_pct: 8`). +- Macro-print windows (FOMC, CPI, ≤30 min before): halt or halve size. + +--- + +## Why This Agent Wins + +1. **Options edge is unoccupied.** The 25D risk reversal and GEX are live institutional + positioning reads that a candlestick chart cannot show. No other agent on the server + trades them. +2. **Every trade is options-aware.** Even the capital-flow strategy checks its read + against options positioning before sizing — when flow and options agree, conviction + is genuine; when they conflict, size comes down. No forced trades. +3. **Solana depth.** The smart-money strategy's on-chain pulse uses verified $90M+/day + SOL/USDC DeFi flow (GeckoTerminal) — far richer than thin XRPL books. +4. **Safe by construction.** Executor position-hold + Risk Engine mean a bad signal read + costs a bounded stop, never a blown account. diff --git a/agents/smart_money_flow/routines/onchain_flow.py b/agents/derive_options_trader/routines/onchain_flow.py similarity index 100% rename from agents/smart_money_flow/routines/onchain_flow.py rename to agents/derive_options_trader/routines/onchain_flow.py diff --git a/agents/derive_options_trader/routines/options_flow.py b/agents/derive_options_trader/routines/options_flow.py new file mode 100644 index 00000000..3170956b --- /dev/null +++ b/agents/derive_options_trader/routines/options_flow.py @@ -0,0 +1,481 @@ +""" +Derive options market read → directional signal for SOL-PERP. + +Pulls live options data from Derive's public API across all active expiries and +computes four signals that cannot be inferred from a price chart alone: + + 1. 25-Delta Risk Reversal (50%) — IV(25Δ call) − IV(25Δ put), near-term weighted. + Positive = smart money is bidding calls = bullish. + 2. Put/Call Open Interest Ratio (35%) — log-scaled, OI-weighted across expiries. + Call-heavy OI = bullish; put-heavy = bearish. + 3. ATM IV Term Structure (15%) — near vs far ATM IV. + Inverted curve = near-term fear = bearish. + 4. Net Gamma Exposure (GEX) — modulates conviction, not direction. + Positive GEX (dealers long gamma) → price gravity, dampen signal (0.75×). + Negative GEX (dealers short gamma) → momentum, amplify signal (1.25×). + +Output: LONG / SHORT / HOLD + composite score (−1 to +1). +""" + +import asyncio +import logging +import math +from datetime import datetime, timezone + +import aiohttp +from pydantic import BaseModel, Field +from telegram.ext import ContextTypes + +from condor.reports import ReportBuilder +from routines.base import RoutineResult + +logger = logging.getLogger(__name__) + +CATEGORY = "Analysis" +DERIVE_API = "https://api.lyra.finance" + + +class Config(BaseModel): + """Derive options market read → directional signal for SOL-PERP.""" + + currency: str = Field(default="SOL", description="Currency to analyze (SOL or ETH)") + perp_instrument: str = Field( + default="SOL-PERP", description="Perpetual instrument to signal" + ) + rr_weight: float = Field( + default=0.50, description="Weight for 25D Risk Reversal (0–1)" + ) + oi_weight: float = Field( + default=0.35, description="Weight for Put/Call OI Ratio (0–1)" + ) + ts_weight: float = Field( + default=0.15, description="Weight for Term Structure (0–1)" + ) + min_threshold: float = Field( + default=0.40, description="Min |composite score| to act; below = HOLD" + ) + + +# ── API helpers ────────────────────────────────────────────────────────────── + + +async def _post(session: aiohttp.ClientSession, path: str, payload: dict) -> dict: + async with session.post( + f"{DERIVE_API}/{path}", + json=payload, + headers={"Content-Type": "application/json"}, + timeout=aiohttp.ClientTimeout(total=15), + ) as resp: + resp.raise_for_status() + return await resp.json() + + +async def _fetch_perp_ticker(session: aiohttp.ClientSession, instrument: str) -> dict: + data = await _post(session, "public/get_ticker", {"instrument_name": instrument}) + return data.get("result") or {} + + +async def _fetch_instruments( + session: aiohttp.ClientSession, currency: str +) -> list[dict]: + data = await _post( + session, + "public/get_instruments", + {"currency": currency, "instrument_type": "option", "expired": False}, + ) + return data.get("result") or [] + + +async def _fetch_tickers( + session: aiohttp.ClientSession, currency: str, expiry_date: str +) -> dict: + data = await _post( + session, + "public/get_tickers", + { + "currency": currency, + "instrument_type": "option", + "expired": False, + "expiry_date": expiry_date, + }, + ) + return (data.get("result") or {}).get("tickers") or {} + + +# ── Option parsing ──────────────────────────────────────────────────────────── + + +def _parse_options(tickers: dict) -> list[dict]: + out = [] + for name, t in tickers.items(): + parts = name.split("-") + if len(parts) < 4: + continue + op = t.get("option_pricing") or {} + stats = t.get("stats") or {} + try: + out.append( + { + "name": name, + "strike": float(parts[2]), + "type": parts[3], # "C" or "P" + "delta": float(op.get("d") or 0), + "gamma": float(op.get("g") or 0), + "iv": float(op.get("i") or 0), + "oi": float(stats.get("oi") or 0), + "vol": float(stats.get("v") or 0), + "mark": float(t.get("M") or 0), + } + ) + except (ValueError, TypeError): + continue + return out + + +# ── Signal calculators ──────────────────────────────────────────────────────── + + +def _compute_25d_rr(opts: list[dict]) -> tuple[float | None, str, str]: + """(rr, call_name, put_name). None if insufficient data.""" + calls = [ + o for o in opts if o["type"] == "C" and o["iv"] > 0 and abs(o["delta"]) > 0.01 + ] + puts = [ + o for o in opts if o["type"] == "P" and o["iv"] > 0 and abs(o["delta"]) > 0.01 + ] + if not calls or not puts: + return None, "", "" + c25 = min(calls, key=lambda x: abs(abs(x["delta"]) - 0.25)) + p25 = min(puts, key=lambda x: abs(abs(x["delta"]) - 0.25)) + return c25["iv"] - p25["iv"], c25["name"], p25["name"] + + +def _compute_pc_oi(opts: list[dict]) -> tuple[float | None, float, float]: + """(score +1=bullish…-1=bearish, call_oi, put_oi).""" + call_oi = sum(o["oi"] for o in opts if o["type"] == "C") + put_oi = sum(o["oi"] for o in opts if o["type"] == "P") + if call_oi + put_oi < 10: + return None, call_oi, put_oi + ratio = (put_oi + 0.1) / (call_oi + 0.1) + # log ratio: negative = call-heavy (bullish), positive = put-heavy (bearish) + score = -math.tanh(math.log(ratio) * 1.5) # flip so +1 = bullish + return score, call_oi, put_oi + + +def _atm_iv(opts: list[dict], spot: float) -> float | None: + atm_calls = [o for o in opts if o["type"] == "C" and o["iv"] > 0] + if not atm_calls: + return None + return min(atm_calls, key=lambda x: abs(x["strike"] - spot))["iv"] + + +def _gex(opts: list[dict], spot: float) -> float: + """Net gamma exposure USD. Positive = dealers long gamma.""" + total = 0.0 + for o in opts: + sign = 1.0 if o["type"] == "C" else -1.0 + total += sign * o["gamma"] * o["oi"] * (spot**2) * 0.01 + return total + + +def _confidence( + composite: float, rr_score: float, oi_score: float, ts_score: float +) -> str: + """How many of the 3 sub-signals agree with the EMITTED direction. + + The reference must be sign(composite), not the dominant vote: with weighted + scores and the GEX amplifier, the composite can point LONG while two of + three raw votes point SHORT — grading agreement against the dominant vote + would then stamp MEDIUM on a signal the majority disagrees with. + """ + votes = [ + 1 if rr_score >= 0.2 else (-1 if rr_score <= -0.2 else 0), + 1 if oi_score >= 0.2 else (-1 if oi_score <= -0.2 else 0), + 1 if ts_score >= 0.1 else (-1 if ts_score <= -0.1 else 0), + ] + emitted = 1 if composite > 0 else (-1 if composite < 0 else 0) + if not emitted: + return "LOW" + agree = sum(1 for v in votes if v == emitted) + return "HIGH" if agree == 3 else ("MEDIUM" if agree == 2 else "LOW") + + +# ── Main ───────────────────────────────────────────────────────────────────── + + +async def run(config: Config, context: ContextTypes.DEFAULT_TYPE) -> str: + try: + async with aiohttp.ClientSession() as session: + perp_data, instruments = await asyncio.gather( + _fetch_perp_ticker(session, config.perp_instrument), + _fetch_instruments(session, config.currency), + ) + except (aiohttp.ClientError, asyncio.TimeoutError) as e: + return f"Derive API unavailable ({type(e).__name__}: {e}) — no options signal this tick" + + spot = float(perp_data.get("index_price") or 0) + if spot <= 0: + return f"Could not fetch spot price for {config.perp_instrument}" + + funding_rate = float((perp_data.get("perp_details") or {}).get("funding_rate") or 0) + + # Find unique active expiry dates + active = [i for i in instruments if i.get("is_active")] + expiry_dates = sorted( + set( + datetime.fromtimestamp( + i["option_details"]["expiry"], tz=timezone.utc + ).strftime("%Y%m%d") + for i in active + if i.get("option_details") + ) + ) + if not expiry_dates: + return "No active options found" + + # Fetch all expiry tickers in parallel + sem = asyncio.Semaphore(6) + + async def fetch_guarded(exp: str) -> tuple[str, dict]: + async with sem: + async with aiohttp.ClientSession() as s: + tickers = await _fetch_tickers(s, config.currency, exp) + return exp, tickers + + results = await asyncio.gather( + *[fetch_guarded(e) for e in expiry_dates], return_exceptions=True + ) + expiry_opts, failed_expiries = {}, [] + for exp, res in zip(expiry_dates, results): + if isinstance(res, BaseException): + logger.warning("options_flow: expiry %s fetch failed: %s", exp, res) + failed_expiries.append(exp) + else: + expiry_opts[exp] = _parse_options(res[1]) + if not expiry_opts: + return ( + f"Derive API unavailable (all {len(expiry_dates)} expiry fetches failed) " + "— no options signal this tick" + ) + + # ── Per-expiry signals ── + today = datetime.now(tz=timezone.utc) + + def dte(exp_str: str) -> int: + return max( + 1, + ( + datetime.strptime(exp_str, "%Y%m%d").replace(tzinfo=timezone.utc) + - today + ).days, + ) + + rr_map, rr_detail, oi_map, iv_map = {}, {}, {}, {} + for exp, opts in expiry_opts.items(): + rr, c_name, p_name = _compute_25d_rr(opts) + if rr is not None: + rr_map[exp] = rr + rr_detail[exp] = (c_name, p_name) + oi_score, c_oi, p_oi = _compute_pc_oi(opts) + if oi_score is not None: + oi_map[exp] = (oi_score, c_oi, p_oi) + iv = _atm_iv(opts, spot) + if iv is not None: + iv_map[exp] = iv + + # ── Composite score ── + # 25D RR: near-term weighted (w = 1/DTE) + rr_num, rr_den = 0.0, 0.0 + for exp, rr in rr_map.items(): + w = 1.0 / dte(exp) + rr_num += math.tanh(rr / 0.05) * w + rr_den += w + rr_score = rr_num / rr_den if rr_den > 0 else 0.0 + + # P/C OI: weighted by log(total OI) + oi_num, oi_den = 0.0, 0.0 + for exp, (score, c_oi, p_oi) in oi_map.items(): + total_oi = c_oi + p_oi + if total_oi < 50: + continue + w = math.log1p(total_oi) + oi_num += score * w + oi_den += w + oi_score = oi_num / oi_den if oi_den > 0 else 0.0 + + # Term structure + ts_score = 0.0 + if len(iv_map) >= 2: + sorted_ivs = [iv_map[e] for e in sorted(iv_map)] + near_iv, far_iv = sorted_ivs[0], sorted_ivs[-1] + if near_iv > far_iv * 1.05: + ts_score = -0.5 # inverted = fear + elif far_iv > near_iv * 1.05: + ts_score = +0.2 # contango = mild bullish + else: + near_iv, far_iv = 0.0, 0.0 + + # GEX from nearest liquid expiry + gex_exp, gex_val = None, 0.0 + for exp in sorted(expiry_opts): + if sum(o["oi"] for o in expiry_opts[exp]) > 100: + gex_exp = exp + gex_val = _gex(expiry_opts[exp], spot) + break + # No liquid expiry → no gamma read → neutral amplifier (never amplify on missing data) + gex_amp = 0.75 if gex_val > 0 else (1.25 if gex_val < 0 else 1.0) + + composite = max( + -1.0, + min( + 1.0, + ( + rr_score * config.rr_weight + + oi_score * config.oi_weight + + ts_score * config.ts_weight + ) + * gex_amp, + ), + ) + + if composite >= config.min_threshold: + direction, emoji = "LONG", "🟢" + elif composite <= -config.min_threshold: + direction, emoji = "SHORT", "🔴" + else: + direction, emoji = "HOLD", "🟡" + + confidence = _confidence(composite, rr_score, oi_score, ts_score) + + # ── Report ──────────────────────────────────────────────────────────────── + builder = ReportBuilder(f"Options Oracle — {config.currency}/USDC") + builder.source("routine", "options_flow") + builder.tags(["options", "signal", config.currency, "perp"]) + builder.manual_order() + + builder.section("SIGNAL", f"Derive options market read → {config.perp_instrument}") + builder.kpi("Direction", f"{emoji} {direction}") + builder.kpi("Composite Score", f"{composite:+.3f}") + builder.kpi("Confidence", confidence) + builder.kpi(f"{config.currency} Spot", f"${spot:.3f}") + builder.kpi("Funding Rate", f"{funding_rate * 100:.4f}%/hr") + + builder.section("SIGNAL BREAKDOWN", "Weighted sub-signals feeding the composite") + builder.kpi("25D Risk Reversal", f"{rr_score:+.3f} (wt {config.rr_weight:.0%})") + builder.kpi("P/C OI Ratio", f"{oi_score:+.3f} (wt {config.oi_weight:.0%})") + builder.kpi("Term Structure", f"{ts_score:+.3f} (wt {config.ts_weight:.0%})") + if gex_exp is not None: + builder.kpi("GEX Amplifier", f"{gex_val:+.1f} → {gex_amp:.2f}×") + else: + builder.kpi("GEX Amplifier", "n/a (no liquid expiry) → 1.00×") + if failed_expiries: + builder.markdown( + f"⚠️ {len(failed_expiries)}/{len(expiry_dates)} expiry fetches failed " + f"({', '.join(failed_expiries)}) — composite computed from partial data." + ) + + # Per-expiry table + exp_rows = [] + for exp in sorted(expiry_opts): + d = dte(exp) + rr_v = rr_map.get(exp) + oi_d = oi_map.get(exp) + iv_v = iv_map.get(exp) + c_oi = oi_d[1] if oi_d else 0 + p_oi = oi_d[2] if oi_d else 0 + exp_rows.append( + { + "Expiry": exp, + "DTE": d, + "ATM IV": f"{iv_v*100:.1f}%" if iv_v else "—", + "25D RR": f"{rr_v:+.4f}" if rr_v is not None else "—", + "Bias": ( + ("BULL" if rr_v and rr_v > 0 else "BEAR") + if rr_v is not None + else "—" + ), + "Call OI": f"{c_oi:.0f}", + "Put OI": f"{p_oi:.0f}", + "P/C Ratio": f"{p_oi/max(c_oi,1):.2f}", + } + ) + + builder.section( + "PER-EXPIRY BREAKDOWN", "Signals across all active option expiry dates" + ) + builder.table( + exp_rows, + ["Expiry", "DTE", "ATM IV", "25D RR", "Bias", "Call OI", "Put OI", "P/C Ratio"], + ) + + # IV surface for nearest liquid expiry + if gex_exp: + surf_opts = [ + o + for o in expiry_opts[gex_exp] + if o["iv"] > 0 and abs(o["strike"] - spot) / spot < 0.30 + ] + surf_rows = sorted( + [ + { + "Strike": o["strike"], + "Type": o["type"], + "IV %": f"{o['iv']*100:.1f}%", + "Delta": f"{o['delta']:+.3f}", + "OI": f"{o['oi']:.0f}", + "Vol 24h": f"{o['vol']:.1f}", + } + for o in surf_opts + ], + key=lambda x: (x["Strike"], x["Type"]), + ) + + builder.section( + f"IV SURFACE — {gex_exp}", + "Options within ±30% of spot, nearest liquid expiry", + ) + builder.table(surf_rows, ["Strike", "Type", "IV %", "Delta", "OI", "Vol 24h"]) + + builder.section("METHODOLOGY", "") + builder.markdown( + "**25D Risk Reversal** (50%): IV(25Δ call) − IV(25Δ put), weighted by 1/DTE so " + "near-term expiries dominate. Positive = calls bid = bullish.\n\n" + "**Put/Call OI Ratio** (35%): log(put\\_OI / call\\_OI), OI-magnitude weighted. " + "Call-heavy → bullish; put-heavy → bearish.\n\n" + "**Term Structure** (15%): near vs far ATM IV. " + "Inverted (near > far) = near-term fear = bearish (−0.5). " + "Normal contango = mild bullish (+0.2).\n\n" + "**GEX Amplifier**: dealers long gamma (positive GEX) → price gravity → dampen 0.75×. " + "Dealers short gamma (negative GEX) → momentum → amplify 1.25×.\n\n" + f"Threshold: |composite| ≥ {config.min_threshold} → act; below → HOLD." + ) + + await builder.save() + + gex_str = ( + f"GEX {gex_val:+.0f} ({gex_amp:.2f}×)" + if gex_exp is not None + else "GEX n/a (1.00×)" + ) + summary = ( + f"{emoji} Options Oracle: **{direction}** (score {composite:+.3f} | {confidence} confidence)\n" + f"{config.currency} @ ${spot:.3f} | " + f"25D RR {rr_score:+.3f} | P/C OI {oi_score:+.3f} | TS {ts_score:+.3f} | {gex_str}" + ) + if failed_expiries: + summary += f"\n⚠️ partial data: {len(failed_expiries)}/{len(expiry_dates)} expiry fetches failed" + + return RoutineResult( + text=summary, + sections=[ + {"type": "kpi", "label": "Direction", "value": f"{emoji} {direction}"}, + {"type": "kpi", "label": "Score", "value": f"{composite:+.3f}"}, + {"type": "kpi", "label": "Confidence", "value": confidence}, + { + "type": "kpi", + "label": f"{config.currency} Spot", + "value": f"${spot:.3f}", + }, + {"type": "kpi", "label": "Funding/hr", "value": f"{funding_rate*100:.4f}%"}, + ], + ) diff --git a/agents/smart_money_flow/skills/smart_money_playbook/SKILL.md b/agents/derive_options_trader/skills/smart_money_playbook/SKILL.md similarity index 76% rename from agents/smart_money_flow/skills/smart_money_playbook/SKILL.md rename to agents/derive_options_trader/skills/smart_money_playbook/SKILL.md index 180c0402..5f5fe4e5 100644 --- a/agents/smart_money_flow/skills/smart_money_playbook/SKILL.md +++ b/agents/derive_options_trader/skills/smart_money_playbook/SKILL.md @@ -1,8 +1,8 @@ --- name: smart_money_playbook -description: How to read the Smart-Money Flow composite and translate it into a bounded directional perp decision on any venue (Derive, Hyperliquid, Backpack, Pacifica, …). Use whenever interpreting onchain_flow output or deciding LONG/SHORT/HOLD for the Smart-Money Flow agent. -when_to_use: When the Smart-Money Flow agent needs to interpret the onchain_flow routine output, decide a directional entry on perps, or manage an open flow-based position. -source: agent:smart_money_flow +description: How to read the Smart-Money Flow composite and translate it into a bounded directional perp decision on any venue (Derive, Hyperliquid, Backpack, Pacifica, …). Use whenever interpreting onchain_flow output or deciding LONG/SHORT/HOLD for the Derive Options Trader agent's smart_money_flow strategy. +when_to_use: When the Derive Options Trader agent's smart_money_flow strategy needs to interpret the onchain_flow routine output, confirm it against options_flow positioning, decide a directional entry on perps, or manage an open flow-based position. +source: agent:derive_options_trader --- # Smart-Money Playbook (Directional Perps, any venue) @@ -18,16 +18,21 @@ directional/short side this composite needs.) | Signal | Source | What it tells you | |---|---|---| -| Risk regime | CoinGecko `/global` (mcap 24h, top-asset dominance) | RISK-ON / RISK-OFF / NEUTRAL | +| Risk regime | CoinGecko `/global` (mcap 24h, BTC dominance) | RISK-ON / RISK-OFF / NEUTRAL | | Per-asset flow score | `/coins/markets` volume-to-mcap + 24h change | How hard capital moves in/out of an asset | | Trending momentum | `/search/trending` | What is heating up across the market | | **Solana on-chain pulse** | GeckoTerminal SOL top pools | Crypto-native DeFi flow (vol, momentum, TVL) — the default signal. Solana carries materially deeper liquidity than XRPL. | | XRPL pulse (optional) | XRPL JSON-RPC AMM/wallets | Legacy cross-check, off by default | +| **Options confirmation** | `options_flow` (Derive options API) | 25D risk reversal, put/call OI, term structure, GEX — confirms or fades the flow read | **Flow score scale:** normalized −1 (strong outflow/down) … +1 (strong inflow/up). **Entry threshold (DEMO MODE):** `|flow_score| >= 0.05`, ANY regime — direction is the sign of the flow. If no asset clears 0.05, open the largest-|flow| asset anyway (unless all |flow| < 0.02). +**Options confirmation:** always cross-check the `options_flow` composite before +sizing — full size when options agree with the flow direction, half size when they +strongly disagree (|composite| ≥ 0.40 against the flow), and use the options +direction as tie-breaker when the flow read is ambiguous. ## Decision matrix (Derive perps) diff --git a/agents/derive_options_trader/strategies/options_oracle_operator/strategy.md b/agents/derive_options_trader/strategies/options_oracle_operator/strategy.md new file mode 100644 index 00000000..bd6662d7 --- /dev/null +++ b/agents/derive_options_trader/strategies/options_oracle_operator/strategy.md @@ -0,0 +1,150 @@ +--- +name: Options Oracle Operator +description: Trades SOL-USDC perps on Derive using the options_flow signal — 25D risk + reversal, put/call OI ratio, IV term structure, and GEX composite. 5-minute cadence. +agent_key: claude-acp:sonnet +skills: +- derive_options_trader:smart_money_playbook +default_config: + execution_mode: loop + frequency_sec: 300 + total_amount_quote: 50 + min_order_amount_quote: 10 + max_ticks: 0 + risk_limits: + max_position_size_quote: 50 + max_drawdown_pct: 8 + max_open_executors: 1 + max_leverage: 2 +default_trading_context: '' +created_by: 456181693 +created_at: '2026-08-11T18:28:40.121620+00:00' +--- + +# Options Oracle Operator — Playbook + +You are the **loop strategy** for the Derive Options Trader agent that reads **Derive +options market positioning** and trades **SOL-USDC perpetuals** on `derive_perpetual`. + +`trading_pair: SOL-USDC` and `connector_name: derive_perpetual` are fixed for this +strategy — they are baked into `default_trading_context`. Derive quotes in **USDC**, +not USDT; always use `SOL-USDC`. Minimum order: **0.1 SOL** (~$8–20 depending on price); +size every order above this floor. Before sizing, read live balance from +`get_portfolio_overview`. + +--- + +## Each Tick — Step by Step + +### Step 1 — Run the options read + +``` +manage_routines(action="run", name="options_flow") +``` + +Extract: +- `direction`: LONG / SHORT / HOLD +- `composite_score`: −1 to +1 (negative = bearish, positive = bullish) +- `confidence`: LOW / MEDIUM / HIGH +- SOL spot price (from the report or portfolio overview) + +### Step 2 — Check open positions + +``` +get_portfolio_overview() +``` + +Note any open SOL-USDC position on `derive_perpetual`: side (LONG/SHORT), entry price, +unrealized PnL, time held. + +### Step 3 — Decide + +**No open position:** +| Condition | Action | +|---|---| +| direction=HOLD | Do nothing. Journal reason. | +| confidence=LOW | Do nothing. Journal reason. | +| direction=LONG, confidence≥MEDIUM, score≥+0.40 | Enter LONG | +| direction=SHORT, confidence≥MEDIUM, score≤−0.40 | Enter SHORT | + +**Existing position (same direction):** +- Hold. Check stops. No action unless time limit hit (24h) or stop triggered. + +**Existing position (opposite direction), confidence≥MEDIUM, |score|≥0.40:** +- Close existing position first (market close executor), then enter reverse. + +**Existing position, direction=HOLD:** +- Maintain. Do not close on a HOLD signal alone. + +### Step 4 — Size & enter + +Position sizing: +- confidence=HIGH → `size_quote = total_amount_quote × 0.75` +- confidence=MEDIUM → `size_quote = total_amount_quote × 0.50` +- Clamp: `size_quote` must be ≥ `min_order_amount_quote` (10 USDC). + +Convert to base units: `sol_amount = size_quote / sol_spot`, round down to nearest +0.001 SOL, minimum 0.1 SOL. If `sol_amount < 0.1`, skip — journal "size too small". + +**PositionExecutor call shape (REQUIRED — every key INSIDE `executor_config`; +the risk gate reads ONLY that dict, so a top-level `amount` records $0 exposure +and bypasses the cap):** +```json +manage_executors(action="create", executor_config={ + "connector_name": "derive_perpetual", + "trading_pair": "SOL-USDC", + "side": 1, + "amount": , + "total_amount_quote": , + "leverage": 2, + "controller_id": "", + "triple_barrier_config": { + "take_profit": 0.030, + "stop_loss": 0.025, + "trailing_stop": { "activation_price": 0.015, "trailing_delta": 0.020 }, + "time_limit": 86400 + } +}) +``` + +- `side: 1` = LONG, `side: 2` = SHORT. +- `total_amount_quote` is the quote notional (`size_quote`). The gate does NOT + resolve live prices — it reads `total_amount_quote` (falling back to `amount`) + verbatim and compares it against the $50 cap. Give it the honest quote figure. +- Raise leverage to 3 only if confidence=HIGH **and** |composite_score| ≥ 0.70. +- The Risk Engine enforces `max_position_size_quote` (50) and `max_open_executors` (1) + — do not try to open a second position if one is already open. + +### Step 5 — Manage open positions + +On each tick where a position is already open: +- **Time limit:** 24h — options signals reflect multi-hour to multi-day views. +- **Signal flip:** if direction inverts AND confidence ≥ MEDIUM AND |score| ≥ 0.40 → + close current position, enter reverse on the same tick. +- **Profit management:** the `triple_barrier_config` handles TP (3%) and trail (2% after + +1.5%) automatically. No need to manually scale out unless the executor has filled. +- **Hard stop:** −2.5% is always active in the barrier config. + +### Step 6 — Journal in options terms + +Every tick, write one line to the journal. Examples: + +> *"OPTIONS ORACLE: 25D RR −0.40 (puts bid across 5/6 expiries), P/C OI +0.53 (calls +> dominate Aug28/Sep25), TS +0.20, GEX −2705 (momentum amp 1.25×) → score +0.017, HOLD. +> No new position — signals in conflict."* + +> *"OPTIONS ORACLE: 25D RR +0.18, P/C OI +0.65, TS +0.20, GEX −1800 (amp 1.25×) → +> score +0.62, HIGH confidence → LONG 0.1 SOL-USDC at 2× lev. Barrier: TP 3%, stop −2.5%."* + +--- + +## Default Trading Context + +Trade **SOL/USDC perpetuals on Derive** (`derive_perpetual`) — this is the only market +this strategy trades. Derive quotes in **USDC** not USDT; always use `SOL-USDC`. Minimum +order size: 0.1 SOL; always size above the minimum and within risk limits. Read live +portfolio balance via `get_portfolio_overview` before sizing. One-time setup: connect +`derive_perpetual` via the Hummingbot client (wallet address + private key + subaccount id). +The strategy runs on a **5-minute cadence** — most ticks will be no-ops (options +positioning changes slowly), but the fast loop catches signal flips promptly. + diff --git a/agents/derive_options_trader/strategies/smart_money_flow/strategy.md b/agents/derive_options_trader/strategies/smart_money_flow/strategy.md new file mode 100644 index 00000000..d5fc8e19 --- /dev/null +++ b/agents/derive_options_trader/strategies/smart_money_flow/strategy.md @@ -0,0 +1,139 @@ +--- +name: Smart Money Flow +description: Directional perp strategy on Derive (derive_perpetual). Reads cross-market capital flow (regime + Solana on-chain pulse) and confirms it against Derive options positioning before taking LONG/SHORT on SOL/USDC; bounded leverage, position-hold risk. Tested on Derive mainnet only. +agent_key: claude-acp:sonnet +skills: + - derive_options_trader:smart_money_playbook +default_config: + execution_mode: loop + frequency_sec: 300 + total_amount_quote: 50 + # Conservative default sizing (assumes a 50 USDC balance). Demo wallets may be + # funded with more — size from the live portfolio balance + # (get_portfolio_overview) rather than assuming 50. Per-position quote exposure + # is enforced by the Risk Engine's gate (max_position_size_quote). + min_order_amount_quote: 10 # smallest order placed per attempt + max_ticks: 0 + risk_limits: + max_position_size_quote: 50 # enforced by the Risk Engine; never exceed the funded wallet + max_drawdown_pct: 8 + max_open_executors: 1 # one position at a time on a tiny wallet + max_leverage: 2 # conservative; notional scales with wallet +default_trading_context: | + Trade SOL/USDC perpetuals on Derive (connector `derive_perpetual`) — the ONLY + market this strategy trades. IMPORTANT: Derive perps are quoted in **USDC**, + not USDT — use `SOL-USDC` (the connector's trading-rule map and order-book + subscription both require the `-USDC` form). Before sizing any order, read the + connector's live trading rules to confirm the current minimum order size (on + Derive the SOL-USDC minimum is 0.1 SOL, ~$16 at current prices); an order + below the minimum fails immediately (executor `close_type: FAILED`, "Open order + failed"), so always size above the minimum and within the risk limits. Size the + position from the live portfolio balance (`get_portfolio_overview`); the Risk + Engine enforces `max_position_size_quote` (50) against quote exposure, so pass + `total_amount_quote` with the create (see call shape). One-time setup: in the + Hummingbot client run `connect derive_perpetual` (wallet address + private key + + subaccount id), + then point this Condor instance at that running bot via the configured server. + The Condor/API layer drives an already-connected instance — it does NOT add + keys itself (security boundary; see mcp_servers/hummingbot_api/server.py). + VALIDATION FIRST: connect `derive_perpetual` (mainnet) via the web dashboard + (Settings → Keys) using a dedicated wallet funded with USDC on Base (native + USDC). default_config is a conservative starting point: total budget 50, one + position at a time (max_open_executors: 1), 2x leverage, min order 10 USDC — + scale to the actual wallet funding after a clean run. NOTE: Condor's web UI + filters out testnet connectors (see validation.md), so validation is + mainnet-with-small-size, not testnet. Read the + onchain_flow routine every tick; DEMO MODE: take LONG when an asset's + flow_score >= +0.05 and SHORT when flow_score <= -0.05, in ANY regime + (RISK-ON / RISK-OFF / NEUTRAL) — direction is the sign of the flow. If no + asset clears |flow| >= 0.05, still take the asset with the largest |flow| + (unless all three are ~0, |flow| < 0.02). Do not HOLD while a signal exists. + The on-chain signal is Solana DeFi flow (GeckoTerminal), not XRPL. + Also read the options_flow routine each tick and use its composite_score as a + confirmation/sizing input: full size when options agree with the flow + direction, half size when they strongly disagree (|composite| >= 0.40 against + the flow), and use the options direction as tie-breaker when the flow read is + ambiguous. +--- + +# Smart Money Flow — Playbook + +You are the **smart-money capital-flow strategy** of the Derive Options Trader agent, +trading **perpetuals on Derive** (`derive_perpetual`). Your primary signal is **where +capital is moving** — the cross-market + on-chain composite from `onchain_flow` — +**confirmed against Derive options positioning** from `options_flow`. + +**Motto:** *"Follow the flow, not the chart."* + +## The Smart-Money Flow composite (`onchain_flow`) + +Composite of three layers, pulled once per tick: + +| Layer | Source | What it measures | +|---|---|---| +| Risk Regime | CoinGecko `/global` | Total mcap momentum + top-asset dominance | +| Asset Flow Intensity | CoinGecko `/coins/markets` | vol/mcap ratio, 24h change, trending rank | +| Solana On-Chain Pulse | GeckoTerminal top pools | SOL/USDC pool volume + momentum + TVL | + +**Output:** `direction` (LONG / SHORT / HOLD), `flow_score` (−1 to +1), `best_asset`. + +**Interpretation:** LONG when `flow_score ≥ +0.05`; SHORT when `flow_score ≤ −0.05`. +In demo mode, take the largest |flow_score| asset if no asset clears ±0.05. SOL-USDC only. + +## Each tick + +1. **Run the flow read.** Call `manage_routines(action="run", name="onchain_flow")`. + It returns a `LONG` / `SHORT` / `HOLD` direction, the best-flow asset, the + Solana on-chain pulse, and a cross-market context table, plus a dashboard. +2. **Run the options read.** Call `manage_routines(action="run", name="options_flow")`. + Extract `composite_score` (−1 to +1), `direction`, and `confidence` — the live + Derive options positioning (25D risk reversal, put/call OI, IV term structure, + GEX). This is the confirmation channel, not the primary trigger. +3. **Filter (DEMO MODE — take a position every tick unless flat-risk).** Trade + **SOL-USDC only** — the only market this strategy trades. With no open + position: + - `LONG`: asset `flow_score >= +0.05` (any regime — ignore RISK-ON/RISK-OFF/NEUTRAL) + - `SHORT`: asset `flow_score <= -0.05` (any regime) + - Fallback: if no asset clears |flow| >= 0.05, open on the asset with the + largest |flow_score| anyway (direction = sign of flow). If the flow read is + ambiguous (all |flow| < 0.05) but the options read is decisive + (|composite_score| >= 0.40, confidence >= MEDIUM), take the **options + direction** instead. Only HOLD when all |flow| < 0.02 AND options are below + threshold, or a position is already open. +4. **Confirm against options & size.** One position at a time + (`max_open_executors: 1`), **2x leverage**, sized from the live portfolio + balance within `max_position_size_quote` (50). Options modulate size: + - Options **agree** with the flow direction (same sign, any magnitude) → full + computed size. + - Options **strongly disagree** (|composite_score| >= 0.40 against the flow) → + **halve** the size; journal the conflict. In demo mode do not skip the trade + — the flow signal stays primary. + - Options neutral (|composite| < 0.40) → full size, note "options neutral". + Never exceed the funded wallet. Open a `PositionExecutor`. + **Call shape (REQUIRED — matches the risk gate):** + - Put `"controller_id": ""` **INSIDE** + `executor_config` (the gate accepts top-level too, but inside is canonical). + - Pass **`total_amount_quote`** (the quote notional, e.g. ~$16 for 0.1 SOL at + current price) **AND** `amount` in **BASE units**: **0.1 SOL** (= Derive's + min order). The gate does NOT resolve live prices — it reads + `total_amount_quote` (falling back to `amount`) verbatim from inside + `executor_config` and compares it against the $50 cap, so omitting + `total_amount_quote` makes the gate compare base units against quote + dollars and corrupts exposure accounting. Give it the honest quote figure. + - Set `leverage: 2`, `side: 1` (LONG) / `2` (SHORT), `connector_name: + "derive_perpetual"`, `trading_pair: "SOL-USDC"`, plus a + `triple_barrier_config` (TP/trail/stop per step 5). + The Risk Engine auto-blocks anything over limit + (`max_position_size_quote`: 50). +5. **Manage.** 50% take-profit at +2%, trail 2% after +1.5% in profit, hard stop + −2.5%. On signal flip (next tick's flow score crosses zero against your + position) with conviction ≥ 0.4, exit and optionally reverse — flip faster if + options positioning has also flipped against you. Max 8h hold. +6. **Journal the flow thesis** — one line per tick in flow + options terms, e.g. + *"RISK-ON; SOL flow +0.52; Solana pulse +0.44; options +0.31 (agree) → LONG + SOL-USDC full size."* + +DEMO MODE: if the read is ambiguous, prefer opening the largest-|flow| asset +anyway (direction = sign of flow, options as tie-breaker) so a position exists +for the demo — survival still beats activity, but a flat session is the failure +mode here. diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/CHANGELOG.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/CHANGELOG.md new file mode 100644 index 00000000..bfa8e15d --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/CHANGELOG.md @@ -0,0 +1,82 @@ +# Changelog + +All notable changes to the gate-exchange-marketanalysis skill are documented here. + +Format: date-based versioning (`YYYY.M.DD`). Same-day releases may use a sequential suffix: `YYYY.M.DD-1`, `YYYY.M.DD-2`, etc. + +--- + +## [2026.3.11-1] - 2026-03-11 + +### Changed + +- **`gate-cli` command names** — Aligned with new gate-cli interface naming: + - Spot: `get_spot_*` → `cex_spot_get_spot_*` (e.g. `get_spot_order_book` → `gate-cli cex spot market orderbook`, `get_spot_tickers` → `gate-cli cex spot market tickers`, `get_spot_candlesticks` → `gate-cli cex spot market candlesticks`, `get_spot_trades` → `gate-cli cex spot market trades`). + - Futures: `get_futures_*` / `list_futures_*` → `cex_fx_*` (e.g. `get_futures_contract` → `gate-cli cex futures market contract`, `get_futures_order_book` → `gate-cli cex futures market orderbook`, `get_futures_tickers` → `gate-cli cex futures market tickers`, `get_futures_candlesticks` → `gate-cli cex futures market candlesticks`, `get_futures_trades` → `gate-cli cex futures market trades`, `get_futures_funding_rate` → `gate-cli cex futures market funding-rate`, `list_futures_liq_orders` → `gate-cli cex futures market liquidations`, `get_futures_premium_index` → `gate-cli cex futures market premium`). + - Updated in `SKILL.md`, `references/scenarios.md`, `README.md`, and `CHANGELOG.md`. + +--- + +## [2026.3.7-1] - 2026-03-07 + +### Scope + +- Case 8 adds **slippage simulation**: market-order fill vs order book, slippage reported as deviation from best ask (points and %). Spot and futures supported. **Requires both currency pair and quote amount** from the user; no defaults — when either is missing, prompt the user instead of running the simulation. +- Case 9 adds **K-line breakout / support–resistance** analysis from candlesticks and tickers. +- Case 10 adds **liquidity + weekend vs weekday** comparison using order book, 90d candlesticks, and tickers. + +### Added + +- **Case 8: Slippage simulation** — market-order slippage vs best ask + - Trigger: e.g. "slippage simulation", "market buy $10K, how much slippage?", "ADA_USDT slippage simulation" + - **Spot:** `gate-cli cex spot market orderbook` → `gate-cli cex spot market tickers`; **Futures:** `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market tickers` + - Logic: walk ask ladder for quote amount Q; volume-weighted avg price; slippage = avg price − ask1 (points and %) + - Output: simulation inputs, fill summary, slippage vs best ask, conclusion +- Scenario 8.1: spot slippage simulation (e.g. ADA_USDT / ETH market buy $10K) +- Scenario 8.2: futures slippage simulation (perpetual/contract market long) +- Scenario 8.3: missing pair or amount — prompt user (do not call `gate-cli`; ask for pair and/or quote amount; do not default to $10K) +- **Case 9: K-line breakout / support–resistance** — analyze breakout and support/resistance from recent K-line + - Trigger: e.g. "Based on recent K-line, does SOL/USDT show signs of breaking out upward? Analyze support and resistance." + - **Spot:** `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`; **Futures:** `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` + - Logic: historical candlesticks for support/resistance; 24h price, volume, change for momentum and breakout signs + - Output: K-line context, support & resistance table, momentum (24h), breakout assessment +- **Case 10: Liquidity + weekend vs weekday** — evaluate liquidity and compare weekend vs weekday + - Trigger: e.g. "Evaluate ETH liquidity on the exchange and compare weekend vs weekday." + - **Spot:** `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks`(90d) → `gate-cli cex spot market tickers`; **Futures:** `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market candlesticks`(90d) → `gate-cli cex futures market tickers` + - Logic: order book for current depth; 90d candlesticks split by weekend vs weekday for volume and return; compare and summarize + - Output: current liquidity, 90-day weekend vs weekday table, comparison, conclusion + +### Changed + +- **`gate-cli` command names** — Corrected to match gate-cli: `list_futures_funding_rate` → `get_futures_funding_rate`; `list_futures_premium_index` → `get_futures_premium_index`. Updated in `references/scenarios.md` and README.md. (`list_futures_liq_orders` is correct per `gate-cli`.) +- **Pure English** — all trigger phrases and report templates in SKILL.md and `references/scenarios.md` are in English. +- **Versioning** — version and `updated` follow current date (`YYYY.M.DD`). +- **Case 8 required inputs** — currency pair and quote amount both required; if either missing, prompt user (no default pair, no default amount e.g. $10K). SKILL.md Execution step 3 and Domain Knowledge (Case 8) updated accordingly. + +### Audit + +- Case 8 uses gate-cli only (`gate-cli cex spot market orderbook` / `gate-cli cex futures market orderbook`, `gate-cli cex spot market tickers` / `gate-cli cex futures market tickers`). +- No `gate-cli` calls when pair or amount is missing; user is prompted first. +- All analysis is read-only; no trading operations. + +--- + +## [2026.3.5-1] - 2026-03-05 + +### Scope + +This skill supports **market tape analysis only** (read-only): liquidity, momentum, liquidation, funding arbitrage, basis, manipulation risk, order book explainer. No trading operations. + +### Added +- Initial release (market tape analysis, seven scenarios) +- Routing-based SKILL.md with document loading from `references/scenarios.md` +- **Seven analysis modules:** Liquidity, Momentum, Liquidation monitoring, Funding arbitrage, Basis, Manipulation risk, Order book explainer +- Smart spot/futures market detection (perpetual/contract keywords) +- `gate-cli` call order and Report Template defined in `references/scenarios.md` +- Domain knowledge and safety rules + +### Audit + +- Uses gate-cli tools only; all analysis is read-only +- No trading operations or credential handling in this skill + diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/README.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/README.md new file mode 100644 index 00000000..2e5fe2a5 --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/README.md @@ -0,0 +1,186 @@ +# Gate Exchange MarketAnalysis + +## Overview + +An AI Agent skill that provides market tape analysis on [Gate](https://www.gate.com), covering ten scenarios: liquidity, momentum, liquidation monitoring, funding rate arbitrage, basis (spot–futures) monitoring, manipulation risk, order book explanation, slippage simulation, K-line breakout/support–resistance, and liquidity with weekend vs weekday. All scenarios use a defined **`gate-cli` call order and output format** in `references/scenarios.md`. + +--- + +### Core Capabilities + +| Capability | Description | Example | +|------------|-------------|---------| +| **Liquidity analysis** | Order book depth, 24h vs 30d volume, slippage | "How is ETH liquidity?" | +| **Momentum** | Buy vs sell share, funding rate | "Is BTC more long or short in 24h?" | +| **Liquidation monitoring** | 1h liq vs baseline, squeeze, wicks | "Recent liquidations?" | +| **Funding arbitrage** | Rate + volume, spot–futures spread | "Any arbitrage opportunities?" | +| **Basis monitoring** | Spot–futures price, premium index | "What is the basis for BTC?" | +| **Manipulation risk** | Depth/volume ratio, large orders | "Is this coin easy to manipulate?" | +| **Order book explainer** | Bids/asks, spread, depth | "Explain the order book" | +| **Slippage simulation** | Market-order slippage vs best ask (pair + quote amount required) | "ADA_USDT slippage for $10K market buy?" | +| **K-line breakout / support–resistance** | Candlesticks + tickers; support/resistance; breakout momentum | "Does SOL/USDT show breakout signs? Analyze support and resistance." | +| **Liquidity + weekend vs weekday** | Order book + 90d candlesticks + tickers; weekend vs weekday volume/return | "Evaluate ETH liquidity and compare weekend vs weekday." | + +> 📊 **Ten scenarios (Case 1–10):** Ask about liquidity, momentum, liquidation, arbitrage, basis, manipulation risk, order book, slippage simulation, K-line breakout/support–resistance, or liquidity vs weekend/weekday; the skill routes to the right case and follows `references/scenarios.md`. + +--- + +## Architecture + +``` +Natural Language Input + ↓ +Intent Routing (Case 1–10, spot vs futures) + ↓ +gate-cli commands + ├── `gate-cli cex spot market orderbook` / `gate-cli cex futures market orderbook` + ├── `gate-cli cex spot market tickers` / `gate-cli cex futures market tickers` + ├── `gate-cli cex spot market candlesticks` / `gate-cli cex futures market candlesticks` + ├── `gate-cli cex spot market trades` / `gate-cli cex futures market funding-rate` + ├── `gate-cli cex futures market liquidations` + └── `gate-cli cex futures market premium` + ↓ +Analysis & Judgment Logic + ↓ +Structured Report → Natural language response +``` + +**Sub-Modules:** `references/scenarios.md` — `gate-cli` call order, parameters, required fields, and report templates per case. + +--- + +## Agent Use Cases + +### 1. Liquidity check +> "How is ETH liquidity?" + +Depth levels, 24h vs 30d volume, slippage; liquidity rating. For perpetual/contract, use futures order book and candlesticks/tickers. + +### 2. Momentum (buy vs sell) +> "Is BTC more long or short in 24h, and is it sustainable?" + +Trades → buy/sell share; tickers, candlesticks, order book top 10, funding rate for bias and sustainability. + +### 3. Liquidation monitoring +> "Recent liquidations?" + +Liquidation orders (if `gate-cli` provides), candlesticks, tickers; anomaly and squeeze labels. + +### 4. Funding arbitrage scan +> "Any arbitrage opportunities?" + +Screen by |rate| and volume; spot tickers and order book; exclude thin books. + +### 5. Basis (spot–futures) +> "What is the basis for BTC?" + +Spot and futures tickers, premium index; current vs history, widening/narrowing. + +### 6. Manipulation risk +> "Is this coin easy to manipulate?" + +Depth ratio (top 10 / 24h volume); large and consecutive same-side trades. + +### 7. Order book explainer +> "Explain the order book" + +Live order book (e.g. limit=10) + ticker; explain bids/asks, spread, depth. + +### 8. Slippage simulation +> "ADA_USDT slippage for a $10K market buy?" + +Requires pair and quote amount. Spot or futures: order book → tickers (futures: `gate-cli cex futures market contract` first for quanto_multiplier). Walk ask ladder; report slippage vs best ask. + +### 9. K-line breakout / support–resistance +> "Does SOL/USDT show signs of breaking out? Analyze support and resistance." + +Candlesticks → tickers; derive support/resistance from OHLC; use 24h price and volume for momentum and breakout assessment. + +### 10. Liquidity + weekend vs weekday +> "Evaluate ETH liquidity and compare weekend vs weekday." + +Order book + 90d candlesticks + tickers (futures: `gate-cli cex futures market contract` first). Split days into weekend vs weekday; compare volume and return. + +--- + +## Quick Start + +### Prerequisites + +1. `gate-cli` installed and configured (`gate-cli config init` or `GATE_API_KEY` / `GATE_API_SECRET`). Install via `sh ./setup.sh` from this skill directory if needed. +2. No extra dependencies. + +### Example Prompts + +``` +# Liquidity +"How is ETH liquidity?" +"BTC perpetual depth" + +# Momentum +"BTC 24h more long or short, sustainable?" + +# Liquidation +"Recent liquidations?" + +# Arbitrage +"Any funding rate arbitrage opportunities?" + +# Basis +"What is the basis for ETH?" + +# Manipulation +"Is PEPE easy to manipulate?" + +# Order book +"Explain the order book with an example" + +# Slippage simulation (pair + amount required) +"ADA_USDT contract slippage: if I market buy $20K, how much slippage?" + +# K-line breakout / support–resistance +"Based on recent K-line, does SOL/USDT show breakout? Analyze support and resistance." + +# Liquidity + weekend vs weekday +"Evaluate ETH contract liquidity and compare weekend vs weekday." +``` + +See `references/scenarios.md` for full `gate-cli` call order and report templates. + +--- + +## File Structure + +``` +gate-exchange-marketanalysis/ +├── README.md # This file +├── SKILL.md # Skill routing and instructions +├── CHANGELOG.md # Version history +└── references/ + ├── scenarios.md # `gate-cli` call order, judgment logic, report templates per case + └── case-test-report.md # Optional: simulation test summary +``` + +--- + +## Security + +- No external scripts or executable code +- Uses gate-cli tools only — no direct API calls +- No credential handling in chat — configure **`gate-cli`** on the host (`gate-cli config init` or `GATE_API_KEY` / `GATE_API_SECRET`) for authenticated market reads where required +- Read-only market data analysis, no trading operations +- No file system writes +- No data collection, telemetry, or analytics + +## Authentication + +Users should configure their Gate API key in the gate-cli settings (see [gate-cli](https://github.com/gate/gate-cli) for setup instructions). All `gate-cli` commands used by this skill access public market data and do **not** require authentication. + +## Source + +- **Repository**: [github.com/gate/gate-skills](https://github.com/gate/gate-skills) +- **Publisher**: [Gate.com](https://www.gate.com) + +## License + +MIT diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/SKILL.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/SKILL.md new file mode 100644 index 00000000..9ddf3cba --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/SKILL.md @@ -0,0 +1,172 @@ +--- +name: gate-exchange-marketanalysis +description: "Gate Exchange market analysis tool. Use when the user asks for deep market metrics like liquidity, slippage, funding arbitrage, or manipulation risk. Triggers on 'liquidity', 'depth', 'slippage', 'momentum', 'buy/sell pressure', 'squeeze', 'funding rate', 'arbitrage', 'basis', 'premium'." +user-invocable: true +disable-model-invocation: false +metadata: + openclaw: + emoji: "💱" + os: + - darwin + - linux + primaryEnv: GATE_API_KEY + requires: + bins: + - gate-cli + env: + - GATE_API_KEY + - GATE_API_SECRET + + install: + - kind: download + os: + - linux + url: "https://github.com/gate/gate-cli/releases/download/v0.6.2/gate-cli_0.6.2_linux_amd64.tar.gz" + bins: + - gate-cli + targetDir: "bin" + label: "Download gate-cli (Linux x64)" + - kind: download + os: + - linux + url: "https://github.com/gate/gate-cli/releases/download/v0.6.2/gate-cli_0.6.2_linux_arm64.tar.gz" + bins: + - gate-cli + targetDir: "bin" + label: "Download gate-cli (Linux arm64)" + - kind: download + os: + - darwin + url: "https://github.com/gate/gate-cli/releases/download/v0.6.2/gate-cli_0.6.2_darwin_amd64.tar.gz" + bins: + - gate-cli + targetDir: "bin" + label: "Download gate-cli (macOS Intel)" + - kind: download + os: + - darwin + url: "https://github.com/gate/gate-cli/releases/download/v0.6.2/gate-cli_0.6.2_darwin_arm64.tar.gz" + bins: + - gate-cli + targetDir: "bin" + label: "Download gate-cli (macOS Apple Silicon)" +--- + +### Resolving `gate-cli` (binary path) + +Resolve **`gate-cli`** in order: **(1)** **`command -v gate-cli`** and **`gate-cli --version`** succeeds; **(2)** **`${HOME}/.local/bin/gate-cli`** if executable; **(3)** **`${HOME}/.openclaw/skills/bin/gate-cli`** if executable. Canonical rules: [`exchange-runtime-rules.md`](https://github.com/gate/gate-skills/blob/master/skills/exchange-runtime-rules.md) §4 (or [`gate-runtime-rules.md`](https://github.com/gate/gate-skills/blob/master/skills/gate-runtime-rules.md) §4). + + +# gate-exchange-marketanalysis + +## General Rules + +⚠️ STOP — You MUST read and strictly follow the shared runtime rules before proceeding. +Do NOT select or call any tool until all rules are read. These rules have the highest priority. +→ Read [gate-runtime-rules.md](https://github.com/gate/gate-skills/blob/master/skills/gate-runtime-rules.md) +- **Only use the `gate-cli` commands explicitly listed in this skill.** Commands not documented here must NOT be run for these workflows, even if other interfaces expose them. + +Market tape analysis covering thirteen scenarios, such as liquidity, momentum, liquidation monitoring, funding arbitrage, basis monitoring, manipulation risk, order book explanation, slippage simulation, K-line breakout/support–resistance, and liquidity with weekend vs weekday. This skill provides structured market insights by orchestrating Gate MCP tools; call order and judgment logic are defined in `references/scenarios.md`. + +--- + +## Skill Dependencies + + +### Authentication +- **Interactive file setup:** when **`GATE_API_KEY`** and **`GATE_API_SECRET`** are **not** both set on the host, run **`gate-cli config init`** to complete the wizard for API key, secret, profiles, and defaults (see [gate-cli](https://github.com/gate/gate-cli)). +- **Env / flags:** **`gate-cli config init`** is **not** required when credentials are already supplied — e.g. **both** **`GATE_API_KEY`** and **`GATE_API_SECRET`** set on the host, or **`--api-key`** / **`--api-secret`** where supported — never ask the user to paste secrets into chat. +- API Key Required: Not necessarily +- Note: This skill is read-only and primarily uses public market-data surfaces. In many runtimes these calls work without authentication, though some deployments may still route them through an authenticated MCP layer. + +### Installation Check +- **Required:** `gate-cli` (run `sh ./setup.sh` from this skill directory if missing; optional `GATE_CLI_SETUP_MODE=release`). +- Add `$HOME/.openclaw/skills/bin` to **`PATH`** if you invoke `gate-cli` by name (or the directory where [`setup.sh`](./setup.sh) installs it). +- **Credentials:** When **`GATE_API_KEY`** and **`GATE_API_SECRET`** are both set (non-empty) for the host, **do not** require **`gate-cli config init`** for `gate-cli`-backed auth. When **both** are unset or empty and the deployment still expects keys, **remind** the operator to run **`gate-cli config init`** **or** to configure **`GATE_API_KEY`** / **`GATE_API_SECRET`** in the **matching skill** from the skill library (never ask the user to paste secrets into chat). +- **Sanity check:** Confirm the CLI works (e.g. **`gate-cli --version`** or a read-only **`gate-cli cex ...`** market call from this skill) before depending on deeper tool chains. + +## Execution mode + +**Read and strictly follow** [`references/gate-cli.md`](./references/gate-cli.md), then execute this skill's market analysis workflow. + +- `SKILL.md` keeps intent routing, scenario mapping, and output semantics. +- `references/gate-cli.md` is the authoritative `gate-cli` execution contract for tool sequencing, parameter checks, and degradation rules. + +## Sub-Modules + +| Module | Purpose | Document | +|--------|---------|----------| +| **Liquidity** | Order book depth, 24h vs 30d volume, slippage | `references/scenarios.md` (Case 1) | +| **Momentum** | Buy vs sell share, funding rate | `references/scenarios.md` (Case 2) | +| **Liquidation** | 1h liq vs baseline, squeeze, wicks | `references/scenarios.md` (Case 3) | +| **Funding arbitrage** | Rate + volume screen, spot–futures spread | `references/scenarios.md` (Case 4) | +| **Basis** | Spot–futures price, premium index | `references/scenarios.md` (Case 5) | +| **Manipulation risk** | Depth/volume ratio, large orders | `references/scenarios.md` (Case 6) | +| **Order book explainer** | Bids/asks, spread, depth | `references/scenarios.md` (Case 7) | +| **Slippage simulation** | Market-order slippage vs best ask | `references/scenarios.md` (Case 8) | +| **K-line breakout / support–resistance** | Candlesticks + tickers; support/resistance; breakout momentum | `references/scenarios.md` (Case 9) | +| **Liquidity + weekend vs weekday** | Order book + 90d candlesticks + tickers; weekend vs weekday volume/return | `references/scenarios.md` (Case 10) | +| **Technical analysis / what to do** | Short + long timeframe K-line, support/resistance, momentum (price vs volume), funding rate; spot + futures; separate short/long-term advice | `references/scenarios.md` (Case 11) | +| **Multi-asset buy & allocation** | Per-asset ticker + order book + 7d daily candles; futures add funding rate; allocation % and rationale | `references/scenarios.md` (Case 12) | +| **Portfolio allocation review** | Same data as Case 12; assess if allocation is reasonable, adjustment advice, what else to buy if no change | `references/scenarios.md` (Case 13) | + +--- + +## Routing Rules + +Determine which module (case) to run based on user intent: + +| User Intent | Keywords | Action | +|-------------|----------|--------| +| Liquidity / depth | liquidity, depth, slippage | Read Case 1, follow MCP order (use futures APIs if perpetual/contract) | +| Momentum | buy vs sell, momentum | Read Case 2, follow MCP order | +| Liquidation | liquidation, squeeze | Read Case 3 (futures only) | +| Funding arbitrage | arbitrage, funding rate | Read Case 4 | +| Basis | basis, premium | Read Case 5 | +| Manipulation risk | manipulation, depth vs volume | Read Case 6 (spot or futures per keywords) | +| Order book explainer | order book, spread | Read Case 7 | +| Slippage simulation | slippage simulation, market buy $X slippage, how much slippage | Read Case 8 (spot or futures per keywords) | +| K-line breakout / support–resistance | breakout, support, resistance, K-line, candlestick | Read Case 9 (spot or futures per keywords) | +| Liquidity + weekend vs weekday | liquidity, weekend, weekday, weekend vs weekday | Read Case 10 (spot or futures per keywords) | +| Technical analysis / what to do | technical analysis, what to do with BTC, long or short, trading advice, current level | Read Case 11 (spot + futures, short & long timeframes) | +| Multi-asset buy & allocation | watchlist, want to buy, analyze several coins, investment advice, how to allocate budget | Read Case 12 | +| Portfolio allocation review | portfolio, allocation, is my allocation reasonable, how to adjust, what else to buy | Read Case 13 | + +--- + +## Execution + +1. **Match user intent** to the routing table above and determine case (1–13) and market type (spot/futures). +2. **Read** the corresponding case in `references/scenarios.md` for MCP call order and required fields. +3. **Case 8 only:** If the user did **not** specify a **currency pair** or did **not** specify a **quote amount** (e.g. $10K), do not assume defaults — **prompt the user** to provide the missing input(s); see Scenario 8.3 in `references/scenarios.md`. +4. **Call Gate MCP** in the exact order defined for that case. +5. **Apply judgment logic** from scenarios (thresholds, flags, ratings). +6. **Output the report** using that case’s Report Template. +7. **Suggest related actions** (e.g. “For basis, ask ‘What is the basis for XXX?’”). +--- + +## Domain Knowledge (short) + +- **Spot vs futures:** Keywords “perpetual”, “contract”, “future”, “perp” → use futures MCP APIs; “spot” or unspecified → spot. +- **Liquidity (Case 1):** Depth < 10 levels → low liquidity; 24h volume < 30-day avg → cold pair; slippage = 2×(ask1−bid1)/(bid1+ask1) > 0.5% → high slippage risk. +- **Momentum (Case 2):** Buy share > 70% → buy-side strong; 24h volume > 30-day avg → active; funding rate sign + order book top 10 for bias. +- **Liquidation (Case 3):** 1h liq > 3× daily avg → anomaly; one-sided liq > 80% → long/short squeeze; price recovered → wick/spike. +- **Arbitrage (Case 4):** |rate| > 0.05% and 24h vol > $10M → candidate; spot–futures spread > 0.2% → bonus; thin depth → exclude. +- **Basis (Case 5):** Current basis vs history; basis widening/narrowing for sentiment. +- **Manipulation (Case 6):** Top-10 depth total / 24h volume < 0.5% → thin depth; consecutive same-direction large orders → possible manipulation. Use spot by default; use futures when user says perpetual/contract. +- **Order book (Case 7):** Show bids/asks example, explain spread with last price, depth and volatility. +- **Slippage simulation (Case 8):** **Requires both a currency pair and a quote amount** (e.g. ETH_USDT, $10K). If user does not specify either, prompt them — do not assume defaults (e.g. do not default to $10K). Spot: `gate-cli cex spot market orderbook` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market tickers`. Simulate market buy by walking ask ladder; slippage = volume-weighted avg price − ask1 (points and %). +- **K-line breakout / support–resistance (Case 9):** Trigger: e.g. “breakout, support, resistance”, “K-line”, “does X show signs of breaking out?”. Spot: `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers`. Use candlesticks for support/resistance levels; use tickers for 24h price, volume, change (momentum). +- **Liquidity + weekend vs weekday (Case 10):** Trigger: e.g. “liquidity”, “weekend vs weekday”, “compare weekend and weekday”. Spot: `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers`. Order book for current depth; 90d candlesticks to split weekend vs weekday volume and return; compare and summarize. +- **Technical analysis / what to do (Case 11):** Trigger: e.g. "technical analysis, what should I do with BTC", "long or short at current level". Spot: `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` → `gate-cli cex futures market funding-rate`. Use history for support/resistance; compare current price and 24h volume to past for momentum; funding rate for long/short bias; give separate short- and long-term advice. +- **Multi-asset buy & allocation (Case 12):** Trigger: e.g. "I'm watching BTC, ETH, GT and want to buy; analyze and give allocation for $5000". Per asset: `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers` → `gate-cli cex spot market orderbook`; futures: `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market funding-rate`. Spot ticker + order book + 7d daily; add funding for futures; output allocation % and rationale. +- **Portfolio allocation review (Case 13):** Trigger: e.g. "I hold 30% BTC, 30% ETH, 20% DOGE, 15% LTC, 5% USDT; is this allocation reasonable, how to adjust, what else to buy?". Same MCP order as Case 12 (per-asset spot candlesticks + tickers + order_book; futures + funding_rate). Assess allocation, suggest adjustments, or suggest what else to buy if no change. + +--- + +## Important Notes + +- All analysis is read-only — no trading operations are performed. +- Gate MCP must be configured (use `gate-mcp-installer` skill if needed). +- MCP call order and output format are in `references/scenarios.md`; follow them for consistent behavior. +- Always include a disclaimer: analysis is data-based, not investment advice. diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/gate-cli.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/gate-cli.md new file mode 100644 index 00000000..1949d737 --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/gate-cli.md @@ -0,0 +1,95 @@ +--- +name: gate-exchange-marketanalysis-gate-cli +version: "2026.3.30-1" +updated: "2026-03-30" +description: "gate-cli execution specification for market analysis scenarios including liquidity, momentum, liquidation, basis, and slippage simulation." +--- + +# Gate Market Analysis MCP Specification + +## 1. Scope and Trigger Boundaries + +In scope: +- Read-only market analysis for spot/futures +- Scenario-based analysis in `references/scenarios.md` (Cases 1-13) + +Out of scope: +- Any order placement, cancellation, leverage, transfer, or fund movement + +Misroute examples: +- If user asks to execute trades, route to execution skills (spot/futures/copilot). + +## 2. `gate-cli` detection and Fallback + +Detection: +1. Verify read-only market data tool families are available. +2. Probe with the smallest required endpoint for selected market type. + +Fallback: +- If futures data endpoints are unavailable, provide spot-only analysis and disclose limitation. +- If both spot/futures endpoints are unavailable, return framework-level reasoning only and mark as data-unavailable. + +## 2.1 `gate-cli cex …` execution flow (MUST) + +For every documented **`gate-cli cex …`** leaf command, **strictly** follow this order: + +1. **Preflight with `--help`:** Run the same command with **`--help`** immediately after the full `cex …` subcommand path (before any other flags), e.g. `gate-cli cex spot account get --help`, to see whether the CLI marks any flags or arguments as **required**. +2. **If `--help` lists required fields** (e.g. `--currency`): obtain values (ask the user only for non-secret business inputs such as symbol or amount; never ask for API secrets in chat), then run the **real** invocation **without** `--help`, including every required flag, e.g. `gate-cli cex spot account get --currency BTC`. +3. **If `--help` shows no required fields** for that subcommand: you may run the bare **`gate-cli cex …`** (only add optional flags the task still needs for correct semantics). + +**Example:** To run `gate-cli cex spot account get` — first run `gate-cli cex spot account get --help`. If help indicates `--currency` is mandatory, supply it (e.g. `--currency BTC`), then execute `gate-cli cex spot account get --currency BTC`. If nothing is required beyond auth, execute `gate-cli cex spot account get` as documented. + +If `--help` is ambiguous, prefer a safe read-only probe or explicit user clarification—especially before writes. + +## 3. Authentication + +- Public market-data endpoints may work without private account auth. +- If runtime policy requires API key, request valid key before analysis. + +## 4. Optional resources + +No mandatory auxiliary resources. + +## 5. `gate-cli` command specification + +Primary read-only tool families used by scenarios: +- Spot market data: `gate-cli cex spot market orderbook`, `gate-cli cex spot market tickers`, `gate-cli cex spot market candlesticks` +- Futures market data: `gate-cli cex futures market contract`, `gate-cli cex futures market orderbook`, `gate-cli cex futures market tickers`, `gate-cli cex futures market candlesticks`, `gate-cli cex futures market funding-rate` + +Parameter rules: +- Always require explicit `currency_pair` / `contract` target. +- Case 8 slippage simulation requires both symbol and quote amount; do not auto-default. +- Candlestick calls must include timeframe aligned with the chosen scenario. + +Common errors: +- Symbol not found / invalid market type: ask user to confirm symbol. +- Empty order book or stale feed: return insufficient-liquidity/data warning. + +## 6. Execution SOP (Non-Skippable) + +1. Route user intent to one scenario case (1-13). +2. Validate market type (spot or futures) and target symbol. +3. Collect required scenario inputs (especially Case 8 amount gate). +4. Execute tool sequence exactly in scenario order. +5. Apply scenario thresholds/rules to produce GO/CAUTION/BLOCK-like assessment language. +6. Return structured report with explicit data confidence. + +## 7. Output Templates + +```markdown +## Market Analysis Summary +- Scenario: {case_id_and_name} +- Target: {symbol_and_market} +- Key Signals: {liquidity_momentum_basis_liquidation_etc} +- Risk Flags: {high_slippage_thin_depth_event_risk} +- Conclusion: {bullish_bearish_neutral_with_conditions} +- Disclaimer: Data-driven analysis only, not investment advice. +``` + +## 8. Safety and Degradation Rules + +1. Keep this skill strictly read-only. +2. Do not output fabricated prices, volumes, depth, or funding values. +3. When data is missing, degrade to partial analysis and label it clearly. +4. Do not infer execution recommendations as guaranteed outcomes. +5. Keep scenario-specific required inputs as hard gates (no hidden defaults for Case 8 amount/symbol). diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/mcp.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/mcp.md new file mode 100644 index 00000000..0c9f06a3 --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/mcp.md @@ -0,0 +1,83 @@ +--- +name: gate-exchange-marketanalysis-mcp +version: "2026.3.30-1" +updated: "2026-03-30" +description: "MCP execution specification for market analysis scenarios including liquidity, momentum, liquidation, basis, and slippage simulation." +--- + +# Gate Market Analysis MCP Specification + +## 1. Scope and Trigger Boundaries + +In scope: +- Read-only market analysis for spot/futures +- Scenario-based analysis in `references/scenarios.md` (Cases 1-13) + +Out of scope: +- Any order placement, cancellation, leverage, transfer, or fund movement + +Misroute examples: +- If user asks to execute trades, route to execution skills (spot/futures/copilot). + +## 2. MCP Detection and Fallback + +Detection: +1. Verify read-only market data tool families are available. +2. Probe with the smallest required endpoint for selected market type. + +Fallback: +- If futures data endpoints are unavailable, provide spot-only analysis and disclose limitation. +- If both spot/futures endpoints are unavailable, return framework-level reasoning only and mark as data-unavailable. + +## 3. Authentication + +- Public market-data endpoints may work without private account auth. +- If runtime policy requires API key, request valid key before analysis. + +## 4. MCP Resources + +No mandatory MCP resources. + +## 5. Tool Calling Specification + +Primary read-only tool families used by scenarios: +- Spot market data: `cex_spot_get_spot_order_book`, `cex_spot_get_spot_tickers`, `cex_spot_get_spot_candlesticks` +- Futures market data: `cex_fx_get_fx_contract`, `cex_fx_get_fx_order_book`, `cex_fx_get_fx_tickers`, `cex_fx_get_fx_candlesticks`, `cex_fx_get_fx_funding_rate` + +Parameter rules: +- Always require explicit `currency_pair` / `contract` target. +- Case 8 slippage simulation requires both symbol and quote amount; do not auto-default. +- Candlestick calls must include timeframe aligned with the chosen scenario. + +Common errors: +- Symbol not found / invalid market type: ask user to confirm symbol. +- Empty order book or stale feed: return insufficient-liquidity/data warning. + +## 6. Execution SOP (Non-Skippable) + +1. Route user intent to one scenario case (1-13). +2. Validate market type (spot or futures) and target symbol. +3. Collect required scenario inputs (especially Case 8 amount gate). +4. Execute tool sequence exactly in scenario order. +5. Apply scenario thresholds/rules to produce GO/CAUTION/BLOCK-like assessment language. +6. Return structured report with explicit data confidence. + +## 7. Output Templates + +```markdown +## Market Analysis Summary +- Scenario: {case_id_and_name} +- Target: {symbol_and_market} +- Key Signals: {liquidity_momentum_basis_liquidation_etc} +- Risk Flags: {high_slippage_thin_depth_event_risk} +- Conclusion: {bullish_bearish_neutral_with_conditions} +- Disclaimer: Data-driven analysis only, not investment advice. +``` + +## 8. Safety and Degradation Rules + +1. Keep this skill strictly read-only. +2. Do not output fabricated prices, volumes, depth, or funding values. +3. When data is missing, degrade to partial analysis and label it clearly. +4. Do not infer execution recommendations as guaranteed outcomes. +5. Keep scenario-specific required inputs as hard gates (no hidden defaults for Case 8 amount/symbol). diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/scenarios.md b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/scenarios.md new file mode 100644 index 00000000..9402ff15 --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/references/scenarios.md @@ -0,0 +1,1247 @@ +# gate-exchange-marketanalysis — Scenarios & MCP Call Specs + +This document defines the **MCP call order, parameters, required fields, and output format** for each scenario. Implementations must call Gate MCP in the order specified under each Case and produce reports according to the templates below. + +**MCP tool names (Gate MCP):** Spot market data use `gate-cli cex spot market orderbook`, `gate-cli cex spot market candlesticks`, `gate-cli cex spot market tickers`, `gate-cli cex spot market trades`. Futures market data use `gate-cli cex futures market contract`, `gate-cli cex futures market orderbook`, `gate-cli cex futures market candlesticks`, `gate-cli cex futures market tickers`, `gate-cli cex futures market trades`. Futures funding/liquidation/premium use `gate-cli cex futures market funding-rate`, `gate-cli cex futures market liquidations`, `gate-cli cex futures market premium`. Call these exact tool names when invoking Gate MCP. + +| Case | Scenario | Core MCP Call Order | +|------|----------|---------------------| +| 1 | Liquidity analysis | `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers` | +| 2 | Momentum (buy vs sell) | `gate-cli cex spot market trades` → `gate-cli cex spot market tickers` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market orderbook` → `gate-cli cex futures market funding-rate` | +| 3 | Liquidation monitoring | `gate-cli cex futures market liquidations` → `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` | +| 4 | Funding rate arbitrage | `gate-cli cex futures market tickers` → `gate-cli cex futures market funding-rate` → `gate-cli cex spot market tickers` → `gate-cli cex spot market orderbook` | +| 5 | Basis (spot vs futures) | `gate-cli cex spot market tickers` → `gate-cli cex futures market tickers` → `gate-cli cex futures market premium` | +| 6 | Manipulation risk | Spot: `gate-cli cex spot market orderbook` → `gate-cli cex spot market tickers` → `gate-cli cex spot market trades`. When user says perpetual/contract: `gate-cli cex futures market orderbook` → `gate-cli cex futures market tickers` → `gate-cli cex futures market trades` | +| 7 | Order book explainer | `gate-cli cex spot market orderbook` → `gate-cli cex spot market tickers` | +| 8 | Slippage simulation | Spot: `gate-cli cex spot market orderbook` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market tickers` | +| 9 | K-line breakout / support–resistance | `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`; `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` | +| 10 | Liquidity + weekend vs weekday | `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`; `gate-cli cex futures market contract` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` | +| 11 | Technical analysis / what to do (short + long timeframe, support/resistance, momentum, funding) | Spot: `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`. Futures: `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` → `gate-cli cex futures market funding-rate` | +| 12 | Multi-asset buy analysis & allocation | Per asset: `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers` → `gate-cli cex spot market orderbook`; futures: `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market funding-rate` | +| 13 | Portfolio allocation review & adjustment | Same as Case 12: spot ticker + order book + 7d daily; futures add funding rate | + +--- + +## Case 1: Liquidity Analysis + +### MCP Call Spec (document-aligned) + +For liquidity analysis, **call Gate MCP in this order** and extract the listed fields; output must follow the Report Template below. + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex spot market orderbook` (spot) | `currency_pair={BASE}_USDT`, `limit=20` | Number of ask/bid levels; top 10 bid/ask depth totals; bid1/ask1 (for spread and slippage) | +| 2 | `gate-cli cex spot market candlesticks` (spot) | `currency_pair={BASE}_USDT`, `interval=1d`, `limit=30` | Last 30 days volume (for 30d avg); latest candle for 24h volume reference | +| 3 | `gate-cli cex spot market tickers` (spot) | `currency_pair={BASE}_USDT` | `last`; `quoteVolume` 24h (USDT); `changePercentage` 24h; `high24h`/`low24h` | +| 4 (optional) | `gate-cli cex spot market trades` (spot) | `currency_pair={BASE}_USDT`, `limit=100` | Recent trade size distribution for "recent flow" and participation | + +**Calculation & judgment** (aligned with SKILL): + +- **API choice**: Use futures APIs (e.g. `gate-cli cex futures market orderbook`) when user says "perpetual" or "contract"; otherwise spot. +- **Slippage** = `2×(ask1−bid1)/(bid1+ask1)×100%`; if > 0.5% → flag "high slippage risk". +- **Depth**: asks/bids depth < 10 levels → flag "low liquidity". +- **24h volume** < 30-day volume average → flag "cold pair". +- **Liquidity rating**: Combine above into 1–5 ⭐. + +**Output**: Must include a "Core metrics" table (order book depth, 24h volume, 30d avg volume, bid-ask spread, slippage + status), "Assessment" (liquidity rating x/5 ⭐), and short "Recommendation". + +--- + +### Scenario 1.1: Spot liquidity query + +**Context**: User wants to know ETH spot trading conditions. + +**Prompt examples**: +- "How is ETH liquidity?" + +**Expected behavior**: +1. Call in order per **MCP Call Spec**: `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers` (optional `gate-cli cex spot market trades`). +2. From order book: level count, top 10 depth, bid1/ask1. +3. From candlesticks: 30d avg volume, 24h volume. +4. From tickers: last, 24h quote volume, change. +5. Compute slippage; apply document logic for status and rating. +6. Output core metrics table + assessment + recommendation per Report Template. + +**Output**: +```markdown +## ETH Liquidity Analysis + +### Core metrics + +| Metric | Value | Status | +|--------|-------|--------| +| Order book depth | 20 levels | OK | +| 24h volume | $485M | Active | +| 30d avg volume | $320M | - | +| Bid-ask spread | 0.02% | Excellent | +| Slippage risk | 0.03% | Very low | + +### Assessment + +**Liquidity rating**: 5/5 ⭐ + +ETH liquidity is excellent, suitable for large size. +``` + +--- + +### Scenario 1.2: Futures liquidity query + +**Context**: User asks about perpetual/contract depth. + +**Prompt examples**: +- "How is BTC perpetual depth?" + +**Expected behavior**: +1. Detect "perpetual/contract" and use **futures** MCP: `gate-cli cex futures market orderbook` (`settle=usdt`, `contract=BTC_USDT`, `limit=20`) → optional `gate-cli cex futures market tickers`, `gate-cli cex futures market candlesticks`(1d, 30). +2. Extract level count, top 10 depth, bid1/ask1; compute slippage. +3. Output core metrics table + liquidity rating per liquidity criteria. + +**Output**: +```markdown +## BTC_USDT Perpetual — Liquidity Analysis + +| Metric | Value | Status | +|--------|-------|--------| +| Order book depth | 50 levels | Excellent | +| Slippage risk | 0.01% | Very low | + +Liquidity rating: 5/5 ⭐ +``` + +--- + +### Scenario 1.3: Low-liquidity / cold pair warning + +**Context**: User queries a low-cap or illiquid pair. + +**Prompt examples**: +- "How is XYZ liquidity?" + +**Expected behavior**: +1. Still follow **Case 1 MCP Call Spec**: `gate-cli cex spot market orderbook` → `gate-cli cex spot market candlesticks` → `gate-cli cex spot market tickers`. +2. If depth < 10 levels, or 24h volume < 30d avg, or slippage > 0.5%, mark 🔴 in core metrics and output risk note + low liquidity rating. + +**Output**: +```markdown +## XYZ Liquidity Analysis + +### Risk notice + +| Metric | Value | Status | +|--------|-------|--------| +| Order book depth | 5 levels | Insufficient depth | +| 24h volume | $15K | Cold pair | +| Slippage risk | 2.3% | High | + +**Liquidity rating**: 1/5 ⭐ + +⚠️ This pair has poor liquidity; large orders will incur significant slippage. +``` + +--- + +## Case 2: Momentum (buy vs sell) + +### MCP Call Spec (document-aligned) + +**Trigger**: "Is BTC more long or short in 24h, and is it sustainable?" For momentum analysis, **call in this order**; use futures APIs when user asks about contract. + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex spot market trades` (spot) / `gate-cli cex futures market trades` (futures) | `currency_pair` or `contract`+`settle`, `limit=1000` | Buy/sell volume; buy share = buy_volume / total_volume | +| 2 | `gate-cli cex spot market tickers` (spot) / `gate-cli cex futures market tickers` (futures) | Same pair | 24h volume, 24h change | +| 3 | `gate-cli cex spot market candlesticks` (spot) / `gate-cli cex futures market candlesticks` (futures) | `interval=1d`, `limit=30` | 30-day average volume | +| 4 | `gate-cli cex spot market orderbook` (spot) / `gate-cli cex futures market orderbook` (futures) | `limit=20` | Top 10 bid/ask depth for long/short balance | +| 5 | `gate-cli cex futures market funding-rate` or equivalent | When contract | Funding rate; positive → long bias, negative → short bias | + +**Calculation & judgment** (aligned with SKILL): + +- **Buy share > 70%** → "buy-side strong"; sell share > 70% → "sell-side strong". +- **24h volume > 30d avg** → "active". +- **Funding rate** sign + **order book top 10** balance → overall bias and sustainability. + +**Output**: Must include "Buy/sell forces" table, momentum direction, sustainability, and short analysis. + +--- + +### Scenario 2.1: Basic momentum query + +**Context**: User wants to judge short-term long vs short strength. + +**Prompt examples**: +- "Is BTC more long or short in 24h, and is it sustainable?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market trades`/`gate-cli cex futures market trades` → `gate-cli cex spot market tickers`/`gate-cli cex futures market tickers` → `gate-cli cex spot market candlesticks`/`gate-cli cex futures market candlesticks` → `gate-cli cex spot market orderbook`/`gate-cli cex futures market orderbook` → `gate-cli cex futures market funding-rate` (futures when contract). +2. From trades: buy/sell volume, buy share; tickers: 24h volume and change; candlesticks: 30d avg; order book: top 10 long/short depth; funding rate for bias. +3. Apply logic (buy > 70% → buy-side strong; 24h > 30d avg → active; funding + book → direction and sustainability). +4. Output buy/sell table + direction + analysis per Report Template. + +**Output**: +```markdown +## BTC Momentum Analysis + +### Buy/sell forces + +| Metric | Value | +|--------|-------| +| Buy share | 65% | +| Sell share | 35% | +| 24h volume | $2.1B | +| 30d avg volume | $1.8B | +| Activity | Active | + +### Conclusion + +**Momentum direction**: Buy-side slightly ahead + +Buy share 65% but below 70% "strong" threshold; currently long-leaning but not one-sided. Volume above 30d avg; activity is rising. +``` + +--- + +### Scenario 2.2: One-sided strong buy + +**Context**: User asks whether buy side is strong. + +**Prompt examples**: +- "Is ETH buy side strong?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market trades`(ETH_USDT) → `gate-cli cex spot market tickers` → `gate-cli cex spot market candlesticks`. +2. Compute buy/sell share; if buy > 70% mark as buy-side strong. +3. Output buy/sell table + direction (buy-side strong). + +**Output**: +```markdown +## ETH Momentum Analysis + +### Buy/sell forces + +| Metric | Value | +|--------|-------| +| Buy share | 78% | +| Sell share | 22% | + +### Conclusion + +**Momentum direction**: Buy-side strong + +Buy share 78%, well above 70% threshold; clear long-dominated tape. With volume expansion, trend may extend. +``` + +--- + +### Scenario 2.3: Futures momentum query + +**Context**: User explicitly asks about contract momentum. + +**Prompt examples**: +- "BTC contract momentum" + +**Expected behavior**: +1. Detect "contract" and use **futures** MCP: `gate-cli cex futures market trades` (`settle=usdt`, `contract=BTC_USDT`) → `gate-cli cex futures market tickers` → `gate-cli cex futures market candlesticks`. +2. Extract buy/sell share, 24h volume, 30d avg per MCP Call Spec; same output structure, data from futures. + +--- + +## Case 3: Liquidation Monitoring + +### MCP Call Spec (document-aligned) + +**Trigger**: "Recent liquidations?", "Which coins liquidated most?" For liquidation monitoring, **call in this order** (futures only). + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex futures market liquidations` | `settle=usdt`, time range (last 1h; optional 24h for daily baseline) | Liq volume by contract; long (size>0) / short (size<0); 1h total liq | +| 2 | `gate-cli cex futures market candlesticks` | `settle=usdt`, `contract`, `interval=5m`, `limit=12` | Price during liq window, current price, recovery | +| 3 | `gate-cli cex futures market tickers` | `settle=usdt` (or specific contract) | Current price, 24h change | + +**Calculation & judgment** (aligned with SKILL): + +- **1h liq > 3× daily avg** → flag "anomaly". +- **One-sided liq > 80%** (long or short) → flag "long squeeze" or "short squeeze". +- **Price recovered** (vs wick low/high) → flag "wick / spike". + +**Output**: Must include "Market overview" table, "Anomaly contracts" table, and wick analysis when relevant (low, current price, recovery). + +--- + +### Scenario 3.1: Market-wide liquidation overview + +**Context**: User wants a market-wide liquidation view. + +**Prompt examples**: +- "Recent liquidations?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex futures market liquidations` → `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers`. +2. Aggregate liq by contract; long/short share; if daily baseline available, compute 1h vs daily multiple. +3. Apply logic: 1h liq > 3× daily → anomaly; one-sided > 80% → long/short squeeze; price recovered → wick. +4. Output market overview table + anomaly contracts table. + +**Output**: +```markdown +## Liquidation Monitoring + +**Time**: 2026-03-05 15:30 + +### Market overview + +| Metric | Value | +|--------|-------| +| 1h total liq | $45M | +| Long liq | $38M (84%) | +| Short liq | $7M (16%) | + +### Anomaly contracts + +| Contract | Liq volume | Multiple | Type | +|----------|------------|----------|------| +| ETH_USDT | $18M | 4.2x | Long squeeze | +| SOL_USDT | $8M | 3.5x | Long squeeze | + +Long liq 84%; current move is squeezing long leverage. +``` + +--- + +### Scenario 3.2: Wick / spike detection + +**Context**: User suspects a wick/spike (e.g. BTC). + +**Prompt examples**: +- "Did BTC just wick?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex futures market liquidations`(1h, optional filter contract=BTC_USDT) → `gate-cli cex futures market candlesticks`(BTC_USDT, 5m, 12) → `gate-cli cex futures market tickers`. +2. From liq: long/short share; from candlesticks: low, current price; recovery = (current − low) / (pre-spike high − low) or similar. +3. If long-dominated liq and recovery > 80%, output wick analysis (liq table + low/current/recovery + wick conclusion). + +**Output**: +```markdown +## BTC Wick Analysis + +### Liquidation data + +| Metric | Value | +|--------|-------| +| 1h liq | $25M | +| Long liq | $23M (92%) | +| Low | $62,100 | +| Current | $63,800 | +| Recovery | 85% | + +### Conclusion + +**Type**: Wick / spike + +- Long-dominated liq (92%) +- Price recovered 85% +- Typical short wick squeezing long leverage +``` + +--- + +## Case 4: Funding Rate Arbitrage Scan + +### MCP Call Spec (document-aligned) + +**Trigger**: "Any arbitrage opportunities?", "Which coins have extreme funding?" For arbitrage scan, **call in this order**. + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex futures market tickers` | `settle=usdt` | All contracts' funding_rate, 24h volume | +| 2 | `gate-cli cex futures market funding-rate` or equivalent | For candidates / full market | Rate details | +| 3 | `gate-cli cex spot market tickers` (spot) | Per candidate `currency_pair={BASE}_USDT` | Spot last; spot–futures spread | +| 4 | `gate-cli cex spot market orderbook` (spot) | For top candidates `currency_pair`, `limit=20` | Top 10 depth; exclude if depth too thin | + +**Calculation & judgment** (aligned with SKILL): + +- **|rate| > 0.05% and 24h vol > $10M** → candidate. +- **Spot–futures spread > 0.2%** → bonus. +- **Book depth too thin** → exclude. + +**Output**: Must include "Arbitrage opportunities" table, strategy note (long basis / short basis), and risk disclaimer. + +--- + +### Scenario 4.1: Market-wide arbitrage scan + +**Context**: User wants to find funding arbitrage opportunities. + +**Prompt examples**: +- "Any arbitrage opportunities?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex futures market tickers` → `gate-cli cex futures market funding-rate` → `gate-cli cex spot market tickers`(candidates) → `gate-cli cex spot market orderbook`(top candidates). +2. Logic: |rate|>0.05% and 24h vol>$10M → candidate; spot–futures spread>0.2% → bonus; thin depth → exclude. +3. Output arbitrage table + strategy + risk note. + +**Output**: +```markdown +## Funding Rate Arbitrage Scan + +**Time**: 2026-03-05 15:30 + +### Top 5 opportunities + +| Contract | Rate | Ann. | Basis | Depth | Strategy | +|----------|------|------|-------|-------|----------| +| DOGE_USDT | +0.15% | 164% | +0.3% | OK | Long basis | +| PEPE_USDT | +0.12% | 131% | +0.2% | Fair | Long basis | +| WIF_USDT | -0.10% | 109% | -0.1% | OK | Short basis | + +### Strategy + +**Long basis**: Short futures + long spot +**Short basis**: Long futures + short spot (borrow) + +⚠️ Risk: Actual PnL must account for fees and execution. +``` + +--- + +### Scenario 4.2: Extreme funding query + +**Context**: User wants coins with extreme funding rates. + +**Prompt examples**: +- "Which coins have extreme funding?" + +**Expected behavior**: +1. Call `gate-cli cex futures market tickers`(settle=usdt); filter |funding_rate| > 0.001 (0.1%). +2. Sort by |rate|; label severity (e.g. extreme positive, high negative). +3. Output "Extreme funding" table (contract, rate, status). + +**Output**: +```markdown +## Extreme Funding + +| Contract | Rate | Status | +|----------|------|--------| +| DOGE_USDT | +0.18% | Extreme positive | +| SHIB_USDT | +0.15% | High positive | +| WIF_USDT | -0.12% | High negative | + +Positive rate > 0.1% means high cost to long; may signal short-term pullback risk. +``` + +--- + +## Case 5: Basis (Spot vs Futures) Monitoring + +### MCP Call Spec (document-aligned) + +**Trigger**: "What is the basis?", "Spot–futures spread." For basis monitoring, **call in this order**. + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex spot market tickers` (spot) | `currency_pair={BASE}_USDT` | Spot `last` | +| 2 | `gate-cli cex futures market tickers` | `settle=usdt`, optional `contract={BASE}_USDT` | Futures price, mark_price, index_price | +| 3 | `gate-cli cex futures market premium` or equivalent | `settle=usdt`, `contract={BASE}_USDT` | premium_index; if history available, for mean and deviation | + +**Calculation & judgment** (aligned with SKILL): + +- **Current basis vs historical mean** (deviation). +- **Basis widening / narrowing** (widening → sentiment heating; narrowing → mean reversion). + +**Output**: Must include "Basis data" table, current vs historical mean, widening/narrowing conclusion, and short recommendation. + +--- + +### Scenario 5.1: Single-coin basis query + +**Context**: User asks for BTC spot–futures spread. + +**Prompt examples**: +- "What is BTC basis?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market tickers`(BTC_USDT) → `gate-cli cex futures market tickers`(usdt, BTC_USDT) → optional `gate-cli cex futures market premium`. +2. Compute basis, basis rate; if premium history available, historical mean. +3. Output basis table + analysis + recommendation per Report Template. + +**Output**: +```markdown +## BTC Spot–Futures Basis + +### Basis data + +| Metric | Value | +|--------|-------| +| Spot | $63,500 | +| Futures | $63,700 | +| Basis | +$200 | +| Basis rate | +0.31% | +| Historical mean | +0.15% | + +### Analysis + +Current basis rate 0.31%, above historical mean 0.15%; **elevated positive basis**. Possible reasons: strong bullish sentiment; suitable for long-basis arbitrage. +``` + +--- + +### Scenario 5.2: Negative basis warning + +**Context**: User queries ETH basis. + +**Prompt examples**: +- "ETH spot–futures spread" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market tickers`(ETH_USDT) → `gate-cli cex futures market tickers`(usdt, ETH_USDT) → optional `gate-cli cex futures market premium`(settle=usdt, contract=ETH_USDT). +2. Compute basis and basis rate; if premium index available, use for context; if negative, output basis table + ⚠️ negative basis warning (bearish / short crowding). + +**Output**: +```markdown +## ETH Spot–Futures Basis + +### Basis data + +| Metric | Value | +|--------|-------| +| Spot | $3,200 | +| Futures | $3,185 | +| Basis | -$15 | +| Basis rate | -0.47% | + +### Notice + +Currently **negative basis** (futures below spot), which often indicates: +- Bearish sentiment +- Or short crowding +``` + +--- + +## Case 6: Manipulation Risk Analysis (Is the coin easy to manipulate?) + +### MCP Call Spec (document-aligned) + +**Trigger**: "How is this coin’s depth vs volume?" / "Is it easy to manipulate?" + +**API choice**: When user mentions **perpetual, contract, futures**, use **futures** tools; otherwise use **spot** tools. + +| Step | MCP Tool (spot) | MCP Tool (futures, when user says perpetual/contract) | Parameters | Required Fields | +|------|-----------------|--------------------------------------------------------|------------|----------------| +| 1 | `gate-cli cex spot market orderbook` | `gate-cli cex futures market orderbook` | Spot: `currency_pair={BASE}_USDT`. Futures: `settle=usdt`, `contract={BASE}_USDT`. `limit=20` | Top 10 bid depth sum, top 10 ask depth sum | +| 2 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | 24h quote volume (quoteVolume) | +| 3 | `gate-cli cex spot market trades` | `gate-cli cex futures market trades` or equivalent | Same pair; `limit=500` (or 24h window) | Trade size distribution; consecutive same-direction large orders | + +**Calculation & judgment** (aligned with SKILL): + +- **Top 10 depth total / 24h volume < 0.5%** → "thin depth". +- **24h trades have consecutive same-direction large orders** → "possible manipulation". + +**Output**: Must include "Depth analysis" table (top 10 depth, 24h volume, depth ratio, assessment), "Large order" summary, and "Manipulation risk" conclusion. + +--- + +### Scenario 6.1: Manipulation risk query + +**Context**: User is concerned about small-cap coin manipulation. + +**Prompt examples**: +- "Is PEPE easy to manipulate?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook`(PEPE_USDT) → `gate-cli cex spot market tickers` → `gate-cli cex spot market trades`(limit=500). +2. Compute depth ratio; from trades identify large and consecutive same-side. +3. Output depth table + large order summary + risk conclusion per Report Template. + +**Output**: +```markdown +## PEPE Manipulation Risk + +### Depth analysis + +| Metric | Value | Assessment | +|--------|-------|------------| +| Top 10 depth | $850K | - | +| 24h volume | $320M | - | +| Depth ratio | 0.27% | Thin | + +### Large orders + +In last 500 trades: +- 3 consecutive large buys (15% of sample) +- Max single: $125K + +### Risk conclusion + +**Manipulation risk**: High + +- Depth ratio < 0.5% implies small size can move price +- Consecutive same-side large orders suggest possible manipulation +``` + +--- + +### Scenario 6.2: Healthy pair (low risk) + +**Context**: User queries a major pair (e.g. BTC). + +**Prompt examples**: +- "How is BTC depth vs volume?" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook`(BTC_USDT) → `gate-cli cex spot market tickers` → optional `gate-cli cex spot market trades`. +2. Compute depth ratio; if > 2% assess as good depth, low manipulation risk. +3. Output depth table + risk conclusion (low). + +**Output**: +```markdown +## BTC Manipulation Risk + +### Depth analysis + +| Metric | Value | Assessment | +|--------|-------|------------| +| Top 10 depth | $85M | - | +| 24h volume | $2.1B | - | +| Depth ratio | 4.0% | Good | + +### Risk conclusion + +**Manipulation risk**: Low + +BTC has ample depth; large size would be needed to move price; manipulation risk is low. +``` + +--- + +### Scenario 6.3: Futures manipulation risk (perpetual/contract) + +**Context**: User asks about manipulation for a **perpetual/contract** (e.g. "BTC contract easy to manipulate?"). + +**Prompt examples**: +- "Is BTC contract easy to manipulate?" +- "How is ETH perpetual depth vs volume?" + +**Expected behavior**: +1. Detect "perpetual" or "contract" and use **futures** MCP: `gate-cli cex futures market contract`(settle=usdt, contract=BTC_USDT) → `gate-cli cex futures market orderbook`(settle=usdt, contract=BTC_USDT, limit=20) → `gate-cli cex futures market tickers` → `gate-cli cex futures market trades` (or equivalent, limit=500). +2. Use `quanto_multiplier` from contract to convert order book size to notional; extract top 10 depth total and 24h volume; from futures trades detect consecutive same-direction large orders. +3. Apply same judgment: depth ratio < 0.5% → thin; consecutive same-side large → possible manipulation. +4. Output depth analysis table + large order summary + manipulation risk conclusion (same structure as 6.1/6.2, data from futures). + +**Output**: Same structure as Scenario 6.1 or 6.2; data source is futures contract, order book, tickers, and trades. + +--- + +## Case 7: Order Book Explainer + +### MCP Call Spec (document-aligned) + +**Trigger**: "Explain the order book", "What is the order book?", "How to read the book?" For order book explainer, **call in this order**. + +| Step | MCP Tool | Parameters | Required Fields | +|------|----------|------------|----------------| +| 1 | `gate-cli cex spot market orderbook` (spot) / `gate-cli cex futures market orderbook` (futures) | `currency_pair` or `contract`+`settle`, `limit=10` | bids/asks sample (price and size per level) | +| 2 | `gate-cli cex spot market tickers` (spot) / `gate-cli cex futures market tickers` (futures) | Same pair | `last` for spread explanation | + +**Interpretation** (aligned with SKILL): + +- Show sample bids/asks (levels and sizes). +- Explain **spread** (bid–ask) using ticker last. +- Fast moves + deep depth → good liquidity. + +**Output**: Must include order book tutorial, live order book example, key metrics (best bid, best ask, spread), and short takeaways. + +--- + +### Scenario 7.1: Beginner explainer + +**Context**: User is new and needs a tutorial. + +**Prompt examples**: +- "Explain the order book" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook` (e.g. BTC_USDT, limit=10) → `gate-cli cex spot market tickers`. +2. Fill order book table and key metrics with live data; add tutorial text (Bids/Asks/Spread, what spread means). +3. Output tutorial + live example + takeaways. + +**Output**: +```markdown +## Order Book Explained + +### What is the order book + +The order book is the exchange’s "list of orders": + +- **Asks**: Sell orders, sorted by price low to high +- **Bids**: Buy orders, sorted by price high to low +- **Spread**: Gap between best ask and best bid + +### Live example (BTC) + +**Asks** ↑ +| Price | Size | Cumulative | +|-------|------|------------| +| 63,550 | 2.5 | 7.8 | +| 63,530 | 1.8 | 5.3 | +| 63,510 | 3.5 | 3.5 | ← Best ask + +------- Last: 63,505 ------- + +**Bids** ↓ +| Price | Size | Cumulative | +|-------|------|------------| +| 63,500 | 4.2 | 4.2 | ← Best bid +| 63,480 | 2.1 | 6.3 | +| 63,460 | 3.0 | 9.3 | + +### Takeaways + +- **Spread** = 63,510 − 63,500 = $10 (0.016%) +- Tighter spread → better liquidity +- Deeper book → less impact from large orders +``` + +--- + +### Scenario 7.2: Specific pair order book + +**Context**: User wants to see a specific pair’s book (e.g. ETH). + +**Prompt examples**: +- "Show ETH order book" + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook`(ETH_USDT, limit=10) → `gate-cli cex spot market tickers`(ETH_USDT). +2. Output ETH live table (asks/bids, price, size, cumulative) + last + spread and short comment (e.g. liquidity, support). + +**Output**: +```markdown +## ETH Order Book + +**Asks** +| Price | Size | Cumulative | +|-------|------|------------| +| 3,205 | 45 | 120 | +| 3,203 | 32 | 75 | +| 3,201 | 43 | 43 | ← Best ask + +--- Last: 3,200 --- + +**Bids** +| Price | Size | Cumulative | +|-------|------|------------| +| 3,200 | 55 | 55 | ← Best bid +| 3,198 | 28 | 83 | +| 3,196 | 40 | 123 | + +Spread: $1 (0.03%) — liquidity good. Bid depth heavier than asks; support below is stronger. +``` + +--- + +## Case 8: Slippage Simulation + +### MCP Call Spec (document-aligned) + +**Trigger**: "slippage simulation", "market buy $X slippage", "how much slippage if I market buy $10K?", e.g. "ADA_USDT slippage simulation: if I market buy $10K, how much slippage?" + +**Required inputs** (both must be provided; do not use defaults): + +- **Currency pair** (e.g. `ETH_USDT`, `ADA_USDT`, `BTC_USDT`): identifies which order book and ticker to use. **If the user does not specify a pair**, prompt them to provide one (e.g. "Please specify a pair, e.g. ETH_USDT, ADA_USDT."). +- **Quote amount** (e.g. $10,000 USDT): the notional to simulate for the market buy. **If the user does not specify an amount**, prompt them to provide one (e.g. "Please specify the quote amount, e.g. $10K USDT."). **Do not assume a default** (e.g. do not default to $10K). + +**API choice**: When user mentions **perpetual, contract, futures**, use **futures** tools; otherwise use **spot** tools. + +| Step | MCP Tool (spot) | MCP Tool (futures, when user says perpetual/contract) | Parameters | Required Fields | +|------|-----------------|--------------------------------------------------------|------------|----------------| +| 1 | `gate-cli cex spot market orderbook` | `gate-cli cex futures market contract` | Spot: `currency_pair={BASE}_USDT`, `limit=50`. Futures: `settle=usdt`, `contract={BASE}_USDT` | Spot: asks (price, size), bid1/ask1. Futures: `quanto_multiplier` (contract size) for ladder notional | +| 2 | — | `gate-cli cex futures market orderbook` | Futures: `settle=usdt`, `contract={BASE}_USDT`, `limit=50` | Asks (price, size) for ladder walk; bid1/ask1 | +| 3 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | `last`, `lowestAsk` (or use ask1 from order book) | + +**Calculation & judgment** (aligned with SKILL): + +- **Order book + latest price**: Use current order book and ticker last / best ask. +- **Simulate market buy for quote amount Q (e.g. $10K USDT)**: Walk the **ask** ladder from best ask upward; at each level fill `amount_i` at `price_i` until cumulative quote volume `sum(price_i × amount_i)` ≥ Q (last level may be partially filled so total cost ≈ Q). +- **Outputs**: Total base filled, volume spent, **volume-weighted average execution price** = total_cost / total_base. +- **Slippage = deviation from best ask**: + - **Price deviation**: `avg_price − ask1` (points in price). + - **Relative deviation**: `(avg_price − ask1) / ask1 × 100%`; optionally in bps: `× 10000`. + +**Output**: Must include "Simulation inputs" (pair, quote amount, ask1), "Fill summary" (total base, avg price), "Slippage" (vs ask1: points and %), and short "Conclusion". + +--- + +### Scenario 8.1: Spot slippage simulation (e.g. ADA_USDT market buy $10K) + +**Context**: User wants to know how much slippage to expect for a market buy of a given USDT amount on spot. + +**Prompt examples**: +- "ADA_USDT slippage simulation: if I market buy $10K, how much slippage?" +- "How much slippage for a $10K market buy in ETH?" + +**Expected behavior**: +1. **Require pair and amount**: If the user did not specify a **currency pair** (e.g. ADA_USDT, ETH_USDT), prompt them to provide one; do not run the simulation or assume a default pair. If the user did not specify a **quote amount** (e.g. $10,000 USDT), prompt them to provide one; do not assume a default (e.g. do not default to $10K). +2. Parse pair (e.g. ADA_USDT, ETH_USDT) and quote amount (e.g. $10,000 USDT) from the user. +3. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook`(pair, limit=50) → `gate-cli cex spot market tickers`(pair). +4. Walk ask ladder until cumulative quote ≥ quote amount; compute total base filled, total cost, volume-weighted avg price. +5. ask1 = first ask price from order book (or ticker lowestAsk). Slippage = avg_price − ask1 (points) and (avg_price − ask1)/ask1 × 100 (%). +6. Output simulation inputs table + fill summary + slippage vs ask1 + conclusion. + +**Output**: +```markdown +## ADA_USDT Slippage Simulation (Spot Market Buy) + +### Simulation inputs + +| Item | Value | +|------|--------| +| Pair | ADA_USDT (spot) | +| Quote amount | $10,000 USDT | +| Best ask | 0.xxxx USDT | + +### Fill summary + +| Metric | Value | +|--------|--------| +| Total base filled | x,xxx ADA | +| Total cost | ~$10,000 USDT | +| Volume-weighted avg price | 0.xxxx USDT | + +### Slippage vs best ask + +| Metric | Value | +|--------|--------| +| Price deviation (points) | +0.xxxx USDT | +| Relative deviation | +x.xx% | + +### Conclusion + +For a $10K market buy, slippage vs best ask is about x.xx% (about x.xxxx points). Slippage can be higher when depth is thin; consider splitting large orders or using limit orders. +``` + +--- + +### Scenario 8.2: Futures slippage simulation (perpetual/contract) + +**Context**: User asks slippage for a **perpetual/contract** market buy (long) of a given USDT amount. + +**Prompt examples**: +- "BTC perpetual market long $50K, how much slippage?" + +**Expected behavior**: +1. **Require pair**: If no contract/pair is specified (e.g. BTC_USDT), prompt the user to provide one; do not assume a default. +2. Detect "perpetual" or "contract" and use **futures** MCP: `gate-cli cex futures market contract`(settle=usdt, contract={pair}) → `gate-cli cex futures market orderbook`(settle=usdt, contract={pair}, limit=50) → `gate-cli cex futures market tickers`(settle, contract). +3. Use `quanto_multiplier` from contract to convert order book size (contracts) to base notional; same ladder logic on **asks** for quote amount; compute avg price, slippage = avg_price − ask1 (points and %). +4. **Output**: Same structure as Scenario 8.1; data source is futures order book + futures tickers. + +--- + +### Scenario 8.3: Missing pair or amount — prompt user + +**Context**: User asks for slippage simulation but does **not** specify a **currency pair** and/or does **not** specify a **quote amount** (e.g. "How much slippage if I market buy $10K?" with no pair; or "ETH_USDT slippage" with no amount). + +**Prompt examples**: +- "How much slippage if I market buy $10K?" (missing pair) +- "ETH_USDT slippage" / "ADA_USDT perpetual slippage simulation" (missing amount) +- "Slippage simulation" (missing both pair and amount) + +**Expected behavior**: +1. Do **not** call MCP. Do **not** assume a default pair or a default amount (e.g. do not default to $10K). +2. Reply with a short prompt asking for the missing input(s): pair and/or quote amount. + +**Output** (when pair is missing, or amount is missing, or both): +```markdown +To run the slippage simulation, I need both: + +1. **Currency pair** (e.g. spot: ETH_USDT, ADA_USDT; or perpetual: BTC_USDT). +2. **Quote amount** (e.g. $10,000 USDT). I will not assume a default — please specify the amount. + +Example: "ETH_USDT slippage for a $10K market buy" or "ADA_USDT perpetual, market long $5K, how much slippage?" +``` + +--- + +## Case 9: K-Line Breakout / Support–Resistance + +### MCP Call Spec (document-aligned) + +**Trigger**: "Based on recent K-line chart, does SOL/USDT show signs of breaking out upward? Analyze support and resistance." + +**API choice**: Use **spot** tools when user asks about spot pair (or unspecified); use **futures** tools when user says perpetual/contract. + +| Step | MCP Tool (spot) | MCP Tool (futures) | Parameters | Required Fields | +|------|-----------------|--------------------|------------|-----------------| +| 1 | `gate-cli cex spot market candlesticks` | `gate-cli cex futures market candlesticks` | Spot: `currency_pair={BASE}_USDT`. Futures: `settle=usdt`, `contract={BASE}_USDT`. `interval=1d` (or 4h), `limit=30–90` | OHLC; volume; identify local highs/lows for support/resistance; trend structure | +| 2 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | `last`; 24h `quoteVolume`; `changePercentage`; `high24h`/`low24h` for momentum context | + +**Calculation & judgment** (aligned with SKILL): + +- **K-line**: Query historical candlesticks; from OHLC identify **support** (recent lows, consolidation floors) and **resistance** (recent highs, consolidation ceilings). +- **Momentum**: Use 24h price, volume, and change from tickers to assess whether current level has breakout momentum (e.g. volume expansion near resistance, price above key levels). + +**Output**: Must include "K-line context" (period, key levels), "Support & resistance" table or list, "Momentum" (24h price, volume, change), and short "Breakout assessment" (e.g. signs of upward breakout or not). + +--- + +### Scenario 9.1: Spot K-line support–resistance (e.g. SOL/USDT) + +**Context**: User asks whether a spot pair shows breakout signs and wants support/resistance from recent K-line. + +**Prompt examples**: +- "Based on recent K-line chart, does SOL/USDT show signs of breaking out upward? Analyze support and resistance." + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market candlesticks`(SOL_USDT, interval=1d or 4h, limit=30–90) → `gate-cli cex spot market tickers`(SOL_USDT). +2. From candlesticks: derive support (e.g. recent lows, swing lows) and resistance (e.g. recent highs, swing highs); note trend structure (higher highs/lows vs lower). +3. From tickers: last, 24h volume, 24h change, high24h/low24h; use to assess momentum (e.g. volume confirmation, price relative to key levels). +4. Output: K-line context + support/resistance levels + momentum summary + breakout assessment (e.g. clear / no clear signs of upward breakout; data-based, not investment advice). + +**Output**: +```markdown +## SOL/USDT — K-Line Support & Resistance + +### K-line context + +- Period: last 30 days (1d) +- Key levels derived from OHLC + +### Support & resistance + +| Type | Level (approx) | Note | +|--------|-----------------|-------------| +| Resistance | $XXX | Recent high | +| Resistance | $XXX | Prior swing | +| Support | $XXX | Recent low | +| Support | $XXX | Consolidation floor | + +### Momentum (24h) + +| Metric | Value | +|----------|---------| +| Last | $XXX | +| 24h vol | $XXX | +| 24h change | +X.XX% | + +### Breakout assessment + +Based on recent K-line and 24h data: [e.g. price near/above resistance with volume expansion suggests upward breakout potential; or: no clear breakout yet, watch resistance and volume]. Analysis is data-based, not investment advice. +``` + +--- + +### Scenario 9.2: Futures K-line support–resistance + +**Context**: User asks the same for a **perpetual/contract** (e.g. SOL_USDT perpetual). + +**Prompt examples**: +- "Based on recent K-line, does SOL perpetual show breakout? Analyze support and resistance." +- "BTC contract: support and resistance from candlesticks?" + +**Expected behavior**: +1. Detect "perpetual" or "contract" and use **futures** MCP: `gate-cli cex futures market candlesticks`(settle=usdt, contract=SOL_USDT, interval=1d, limit=30–90) → `gate-cli cex futures market tickers`(settle=usdt, contract=SOL_USDT). +2. Same logic: derive support/resistance from OHLC; use tickers for 24h price, volume, change; output same structure with futures data. + +--- + +## Case 10: Liquidity + Weekend vs Weekday + +### MCP Call Spec (document-aligned) + +**Trigger**: "Evaluate ETH liquidity on the exchange and compare weekend vs weekday." + +**API choice**: Use **spot** tools when user asks about spot (or unspecified); use **futures** tools when user says perpetual/contract. + +| Step | MCP Tool (spot) | MCP Tool (futures) | Parameters | Required Fields | +|------|-----------------|--------------------|------------|-----------------| +| 1 | `gate-cli cex spot market orderbook` | `gate-cli cex futures market contract` | Spot: `currency_pair={BASE}_USDT`, `limit=20`. Futures: `settle=usdt`, `contract={BASE}_USDT` | Spot: depth, bid1/ask1. Futures: `quanto_multiplier` for depth notional | +| 2 | `gate-cli cex spot market candlesticks` | `gate-cli cex futures market orderbook` | Spot: same pair, `interval=1d`, `limit=90`. Futures: `settle=usdt`, `contract={BASE}_USDT`, `limit=20` | Spot: daily OHLC, volume. Futures: depth levels; top 10 bid/ask totals; bid1/ask1 | +| 3 | `gate-cli cex spot market tickers` | `gate-cli cex futures market candlesticks` | Same pair/contract; `interval=1d`, `limit=90` (or from/to for ~90 days) | Daily OHLC, volume, quote volume; tag weekend vs weekday | +| 4 | — | `gate-cli cex futures market tickers` | Same pair/contract | `last`; 24h volume; current context | + +**Calculation & judgment** (aligned with SKILL): + +- **Order book**: Query depth; summarize current depth (levels, top 10 totals, spread) for **liquidity**. +- **90-day K-line**: From candlesticks, split days into **weekend** (Sat/Sun) vs **weekday** (Mon–Fri). Compute for each group: avg daily return (or sum of returns), avg/sum of volume and quote volume. Compare weekend vs weekday: volatility (e.g. absolute return), volume/quote volume (liquidity difference). + +**Output**: Must include "Current liquidity" (order book depth, spread), "90-day weekend vs weekday" table (e.g. avg daily volume, avg daily return, or similar), "Comparison" summary, and short "Conclusion". + +--- + +### Scenario 10.1: Spot liquidity + weekend vs weekday (e.g. ETH) + +**Context**: User wants ETH liquidity assessment and weekend vs weekday comparison. + +**Prompt examples**: +- "Evaluate ETH liquidity on the exchange and compare weekend vs weekday." + +**Expected behavior**: +1. Call per **MCP Call Spec**: `gate-cli cex spot market orderbook`(ETH_USDT, limit=20) → `gate-cli cex spot market candlesticks`(ETH_USDT, interval=1d, limit=90 or from/to ~90 days) → `gate-cli cex spot market tickers`(ETH_USDT). +2. From order book: depth levels, top 10 bid/ask totals, spread → current liquidity summary. +3. From candlesticks: for each day (timestamp), classify weekend vs weekday; aggregate by group: e.g. avg daily volume, avg daily quote volume, avg absolute daily return or avg daily return; optionally count days. +4. Compare: e.g. "Weekend avg volume vs weekday avg volume"; "Weekend vs weekday volatility/return." +5. Output: Current liquidity table + "90-day weekend vs weekday" table + comparison + conclusion. Include disclaimer: data-based, not investment advice. + +**Output**: +```markdown +## ETH — Liquidity & Weekend vs Weekday + +### Current liquidity + +| Metric | Value | +|------------------|---------| +| Order book depth | XX levels | +| Top 10 bid total | $XXX | +| Top 10 ask total | $XXX | +| Spread | X.XX% | + +### 90-day: Weekend vs weekday + +| Metric | Weekend | Weekday | Note | +|---------------|---------|---------|--------| +| Avg daily vol | $XXX | $XXX | Base | +| Avg daily quote vol | $XXX | $XXX | USDT | +| Avg daily return | +X.XX% | +X.XX% | Or abs return | +| Days count | XX | XX | | + +### Comparison + +- Liquidity: [e.g. current order book depth is good / moderate] +- Weekend vs weekday: [e.g. weekend volume/volatility is lower / higher / similar to weekday]. [One-line summary of volume and volatility difference.] + +### Conclusion + +[Short summary: ETH liquidity on exchange + weekend vs weekday difference.] Analysis is data-based, not investment advice. +``` + +--- + +### Scenario 10.2: Futures liquidity + weekend vs weekday + +**Context**: User asks the same for **perpetual/contract** (e.g. ETH_USDT perpetual). + +**Prompt examples**: +- "Evaluate ETH contract liquidity and compare weekend vs weekday." +- "BTC perpetual: liquidity and weekend vs weekday comparison." + +**Expected behavior**: +1. Detect "perpetual" or "contract" and use **futures** MCP: `gate-cli cex futures market contract`(settle=usdt, contract=ETH_USDT) → `gate-cli cex futures market orderbook`(settle=usdt, contract=ETH_USDT, limit=20) → `gate-cli cex futures market candlesticks`(settle=usdt, contract=ETH_USDT, interval=1d, limit=90) → `gate-cli cex futures market tickers`(settle=usdt, contract=ETH_USDT). +2. Use `quanto_multiplier` from contract to interpret order book depth in notional; same logic: order book for current depth; 90d candlesticks split weekend vs weekday for volume and return; output same structure with futures data. + +--- + +## Case 11: Technical Analysis — What to Do (Short + Long Timeframe, Support/Resistance, Momentum, Funding) + +### MCP Call Spec (document-aligned) + +**Trigger**: "Technical analysis: what should I do with BTC now?", "Should I go long or short at current level?", "Give me a trading recommendation based on technicals." + +**API choice**: Use **spot** and **futures** (query both); spot for price and volume, futures add funding rate for long/short bias. Query short and long timeframes; give separate advice per timeframe. + +| Step | MCP Tool (spot) | MCP Tool (futures) | Parameters | Required Fields | +|------|-----------------|--------------------|------------|-----------------| +| 1 | `gate-cli cex spot market candlesticks` | `gate-cli cex futures market candlesticks` | Spot: `currency_pair={BASE}_USDT`. Futures: `settle=usdt`, `contract={BASE}_USDT`. Short & long: `interval=4h` and `1d`, `limit=30–90` | OHLC; volume; support/resistance (recent highs/lows); trend structure | +| 2 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | `last`; 24h `quoteVolume`; `changePercentage`; compare to history for momentum | +| 3 | — | `gate-cli cex futures market funding-rate` | `contract`+`settle` | Funding rate; positive → long cost high / short bias; negative → short cost high / long bias | + +**Calculation & judgment** (aligned with SKILL): + +- **Support/resistance**: From historical candlesticks (short and long timeframe) identify recent highs, lows, consolidation bounds; assess current price level. +- **Momentum**: Compare current price and 24h volume to past (e.g. 7d/30d average); volume–price confirmation, volume breakout / low-volume pullback. +- **Long/short bias**: Funding rate sign and size; high positive → long crowding, cautious or contrarian; high negative → short crowding, bias long. +- **Short vs long timeframe**: Query both (e.g. 4h and 1d); give short-term action from short timeframe and trend/key levels from long timeframe. + +**Output**: Must include "K-line & key levels" (both timeframes), "Momentum" (current price, 24h volume vs past), "Funding & long/short" (futures only), "Short-term advice" and "Long-term advice". + +--- + +### Scenario 11.1: Technical analysis — what to do (e.g. BTC) + +**Context**: User wants a technical-based recommendation for a pair (e.g. BTC): long/short/wait, short and long timeframe. + +**Prompt examples**: +- "Technical analysis: what should I do with BTC now?" + +**Expected behavior**: +1. **Spot**: Call per **MCP Call Spec**: `gate-cli cex spot market candlesticks`(BTC_USDT, interval=4h and 1d, limit=30–90 each) → `gate-cli cex spot market tickers`(BTC_USDT). +2. **Futures**: Call per **MCP Call Spec**: `gate-cli cex futures market candlesticks`(settle=usdt, contract=BTC_USDT, same timeframes) → `gate-cli cex futures market tickers` → `gate-cli cex futures market funding-rate`(contract=BTC_USDT). +3. From candlesticks: derive support/resistance; from ticker: current price, 24h volume, change; compare to history for momentum; from funding_rate: long/short bias. +4. Output: K-line context + key levels (both timeframes) + momentum conclusion + funding long/short conclusion + short-term recommendation + long-term recommendation per Report Template. + +**Output**: +```markdown +## BTC Technical Analysis — Current Recommendation + +### K-line & key levels (short & long timeframe) + +| Timeframe | Support (approx) | Resistance (approx) | Note | +|-----------|------------------|----------------------|------| +| 4h | $XX,XXX | $XX,XXX | Short-term structure | +| 1d | $XX,XXX | $XX,XXX | Trend & key levels | + +### Momentum (current price vs 24h volume vs past) + +| Metric | Value | Vs past | +|---------------|--------|---------| +| Current price | $XX,XXX | - | +| 24h volume | $X.XB | Above/below 7d avg | +| 24h change | ±X.XX% | - | + +Conclusion: Volume–price [aligned/divergent]; momentum [bullish/bearish/neutral]. + +### Funding & long/short (futures) + +| Contract | Funding rate | Long/short read | +|-----------|--------------|-----------------| +| BTC_USDT | ±0.0X% | Long/short cost elevated; short/long bias | + +### Short-term advice (e.g. 4h) + +[Based on short-term support/resistance and momentum: e.g. near support consider buying, near resistance reduce; or wait.] + +### Long-term advice (e.g. 1d) + +[Based on daily trend and key levels: e.g. uptrend → buy dips; or wait for breakout confirmation.] + +Analysis is data-based, not investment advice. +``` + +--- + +## Case 12: Multi-Asset Buy Analysis & Allocation + +### MCP Call Spec (document-aligned) + +**Trigger**: "I'm watching BTC, ETH and GT and want to buy some; analyze these three and give investment advice; I have $5000, how should I allocate across them?" + +**API choice**: Use **spot** for each asset (ticker + order book + last 7d daily); if user involves **futures** or needs futures view, also use **futures** (candlesticks + tickers + order_book + funding_rate) per asset. + +| Step | MCP Tool (spot) | MCP Tool (futures, when needed) | Parameters | Required Fields | +|------|-----------------|----------------------------------|------------|-----------------| +| 1 | `gate-cli cex spot market candlesticks` | `gate-cli cex futures market candlesticks` | Spot: `currency_pair={BASE}_USDT`, `interval=1d`, `limit=7`. Futures: `settle=usdt`, `contract={BASE}_USDT`, same interval/limit | Last 7d daily OHLC; volume | +| 2 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | `last`; 24h volume; change; liquidity reference | +| 3 | `gate-cli cex spot market orderbook` | `gate-cli cex futures market orderbook` | `limit=20` | Depth; bid-ask spread; large orders | +| 4 | — | `gate-cli cex futures market funding-rate` | `contract`+`settle` | Funding rate; futures add long/short cost | + +**Calculation & judgment** (aligned with SKILL): + +- **Spot**: Gate spot ticker (price, volume, change) + order book (depth, spread) + last 7d daily (trend, volatility). +- **Futures**: If analysis involves futures, add funding rate (positive → long cost high; negative → short cost high). +- **Allocation**: Combine volatility, liquidity, trend and risk per asset; for user’s total amount (e.g. $5000) give suggested weights (e.g. BTC X%, ETH Y%, GT Z%) with brief rationale. + +**Output**: Must include per-asset "Spot overview" (ticker + order book + 7d conclusion), "Futures funding" (if applicable), and "Allocation suggestion" (weights and brief rationale). + +--- + +### Scenario 12.1: Multi-asset analysis & allocation (e.g. BTC, ETH, GT, $5000) + +**Context**: User is watching several assets (e.g. BTC, ETH, GT), plans to buy, states total budget (e.g. $5000); needs analysis and allocation advice. + +**Prompt examples**: +- "I'm watching BTC, ETH and GT and want to buy; analyze these three and give investment advice; I have $5000, how should I allocate across them?" + +**Expected behavior**: +1. Call per **MCP Call Spec** for each of BTC_USDT, ETH_USDT, GT_USDT: `gate-cli cex spot market candlesticks`(interval=1d, limit=7) → `gate-cli cex spot market tickers` → `gate-cli cex spot market orderbook`(limit=20). +2. If futures view needed: for same contracts call `gate-cli cex futures market candlesticks` → `gate-cli cex futures market tickers` → `gate-cli cex futures market orderbook` → `gate-cli cex futures market funding-rate`. +3. From ticker: price and 24h performance; from order book: depth and spread; from 7d daily: short-term trend; from futures: funding rate. +4. Output: per-asset spot overview table + futures funding (if applicable) + allocation suggestion (e.g. BTC 40%, ETH 40%, GT 20% with brief rationale) per Report Template. + +**Output**: +```markdown +## Multi-Asset Analysis & Allocation (BTC / ETH / GT, budget $5000) + +### Per-asset spot overview (ticker + order book + last 7d daily) + +| Asset | Price | 24h change | 24h volume | Order book depth/spread | 7d trend (brief) | +|-------|-------|------------|------------|--------------------------|------------------| +| BTC | $XX | ±X% | $XX | Depth/spread | - | +| ETH | $XX | ±X% | $XX | Depth/spread | - | +| GT | $XX | ±X% | $XX | Depth/spread | - | + +### Futures funding rate (if applicable) + +| Contract | Funding rate | Note | +|-----------|--------------|-------------| +| BTC_USDT | ±X.XX% | Long/short cost | +| ETH_USDT | ±X.XX% | Same | +| GT_USDT | ±X.XX% | Same | + +### Allocation suggestion ($5000 example) + +| Asset | Suggested % | Amount | Brief rationale | +|-------|--------------|---------|------------------------------------| +| BTC | XX% | XXX U | Liquidity, moderate volatility | +| ETH | XX% | XXX U | Correlation with BTC, volatility | +| GT | XX% | XXX U | Smaller cap / volatile; size limit | + +Analysis is data-based, not investment advice. +``` + +--- + +## Case 13: Portfolio Allocation Review & Adjustment + +### MCP Call Spec (document-aligned) + +**Trigger**: "I hold 30% BTC, 30% ETH, 20% DOGE, 15% LTC, 5% USDT; is this allocation reasonable, how should I adjust, and if I don’t need to change it what else can I buy?" + +**API choice**: Same as Case 12 — use **spot** for each held asset (ticker + order book + last 7d daily); add **futures** funding rate when relevant. + +| Step | MCP Tool (spot) | MCP Tool (futures, when needed) | Parameters | Required Fields | +|------|-----------------|----------------------------------|------------|-----------------| +| 1 | `gate-cli cex spot market candlesticks` | `gate-cli cex futures market candlesticks` | Spot: `currency_pair={BASE}_USDT`, `interval=1d`, `limit=7`. Futures: same contract + settle | Last 7d daily OHLC; volume | +| 2 | `gate-cli cex spot market tickers` | `gate-cli cex futures market tickers` | Same pair / contract + settle | Current price; 24h volume; change | +| 3 | `gate-cli cex spot market orderbook` | `gate-cli cex futures market orderbook` | `limit=20` | Depth; spread | +| 4 | — | `gate-cli cex futures market funding-rate` | `contract`+`settle` | Funding rate | + +**Calculation & judgment** (aligned with SKILL): + +- **Spot**: Gate spot ticker + order book + last 7d daily (same as Case 12). +- **Futures**: If user holds or considers futures, add funding rate. +- **Allocation review**: From volatility, correlation, liquidity and current trend per asset, judge whether user’s allocation is too concentrated/diversified or risk too high; state "reasonable" or "suggest adjustment" and direction (e.g. reduce X, add Y or USDT). +- **If no adjustment**: If current allocation is fine, suggest "what else to buy" (e.g. other majors, stable yield) with brief rationale. + +**Output**: Must include per-asset "Spot overview" (same as Case 12), "Allocation assessment" (reasonable / suggest adjustment), "Adjustment suggestion" (if any), "Other names to consider" (if no adjustment). + +--- + +### Scenario 13.1: Portfolio allocation review & adjustment (e.g. BTC, ETH, DOGE, LTC, USDT) + +**Context**: User states current allocation (e.g. 30% BTC, 30% ETH, 20% DOGE, 15% LTC, 5% USDT) and asks if it’s reasonable, how to adjust, and what else to buy if no change. + +**Prompt examples**: +- "I hold 30% BTC, 30% ETH, 20% DOGE, 15% LTC, 5% USDT; is this allocation reasonable, how should I adjust my portfolio, and if I don’t need to change it what else can I buy?" + +**Expected behavior**: +1. Call per **MCP Call Spec** for each of BTC, ETH, DOGE, LTC: `gate-cli cex spot market candlesticks`(interval=1d, limit=7) → `gate-cli cex spot market tickers` → `gate-cli cex spot market orderbook`(limit=20); if futures involved, also call candlesticks → tickers → order_book → funding_rate for the contracts. +2. From 7d performance, liquidity, volatility and correlation per asset, assess user's allocation (e.g. majors 60%, alts 35%, cash 5% — risk acceptable or not). +3. Output: per-asset spot overview → allocation assessment (reasonable / suggest adjustment) → concrete adjustment (what to reduce/add) → if no change, "other names to consider" per Report Template. + +**Output**: +```markdown +## Portfolio Allocation Review & Advice (BTC / ETH / DOGE / LTC / USDT) + +### Per-asset spot overview (ticker + order book + last 7d daily) + +| Asset | Price | 24h change | 24h volume | Order book depth/spread | 7d trend (brief) | +|-------|-------|------------|------------|--------------------------|------------------| +| BTC | $XX | ±X% | $XX | - | - | +| ETH | $XX | ±X% | $XX | - | - | +| DOGE | $XX | ±X% | $XX | - | - | +| LTC | $XX | ±X% | $XX | - | - | + +### Allocation assessment + +Current allocation: BTC 30%, ETH 30%, DOGE 20%, LTC 15%, USDT 5%. + +Conclusion: [Reasonable / Suggest adjustment]. Rationale: [1–2 sentences on concentration, volatility, liquidity, correlation.] + +### Adjustment suggestion (if needed) + +[E.g. reduce DOGE weight, increase USDT for volatility buffer; or keep as is.] + +### If no adjustment, other names to consider + +[E.g. consider adding XXX, YYY for diversification or return; or keep current portfolio.] + +Analysis is data-based, not investment advice. +``` diff --git a/agents/market_making_expert/skills/gate-exchange-marketanalysis/setup.sh b/agents/market_making_expert/skills/gate-exchange-marketanalysis/setup.sh new file mode 100755 index 00000000..29df33a6 --- /dev/null +++ b/agents/market_making_expert/skills/gate-exchange-marketanalysis/setup.sh @@ -0,0 +1,123 @@ +#!/bin/sh +set -e + +REPO="gate/gate-cli" +BINARY="gate-cli" + +# --- Parse flags --- +VERSION="" +while [ $# -gt 0 ]; do + case "$1" in + --version) + if [ -z "$2" ]; then + echo "Error: --version requires a value (e.g. --version v0.3.2)" >&2 + exit 1 + fi + VERSION="$2" + shift 2 + ;; + *) + echo "Unknown argument: $1" >&2 + exit 1 + ;; + esac +done + +# --- Detect OS and arch --- +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + *) + echo "Unsupported architecture: $ARCH" >&2 + exit 1 + ;; +esac + +case "$OS" in + linux|darwin) ;; + *) + echo "Unsupported OS: $OS" >&2 + exit 1 + ;; +esac + +# --- Resolve version --- +if [ -z "$VERSION" ]; then + VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ + | grep '"tag_name"' | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/') +fi + +# Fallback when API is rate-limited, blocked, or grep/sed yields nothing (matches gate-cli v0.6.0 per releases/latest). +if [ -z "$VERSION" ]; then + VERSION="v0.6.0" + echo "setup.sh: GitHub API returned no tag_name; using fallback ${VERSION}" >&2 +fi + +# Strip leading 'v' for the archive filename +BARE_VERSION="${VERSION#v}" +ARCHIVE="${BINARY}_${BARE_VERSION}_${OS}_${ARCH}.tar.gz" +BASE_URL="https://github.com/${REPO}/releases/download/${VERSION}" + +# --- Download --- +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +echo "Downloading ${ARCHIVE}..." +curl -fsSL "${BASE_URL}/${ARCHIVE}" -o "${TMP}/${ARCHIVE}" +curl -fsSL "${BASE_URL}/checksums.txt" -o "${TMP}/checksums.txt" + +# --- Verify checksum --- +echo "Verifying checksum..." +CHECKSUM_LINE=$(grep -F " ${ARCHIVE}" "${TMP}/checksums.txt" || true) +if [ -z "$CHECKSUM_LINE" ]; then + echo "Error: ${ARCHIVE} not found in checksums.txt" >&2 + exit 1 +fi +if command -v shasum > /dev/null 2>&1; then + (cd "$TMP" && echo "$CHECKSUM_LINE" | shasum -a 256 --check --status) +elif command -v sha256sum > /dev/null 2>&1; then + (cd "$TMP" && echo "$CHECKSUM_LINE" | sha256sum --check --status) +else + echo "Warning: no sha256sum or shasum found, skipping checksum verification" >&2 +fi + +# --- Extract --- +tar -xzf "${TMP}/${ARCHIVE}" -C "$TMP" "${BINARY}" + +# --- Install --- +install_bin() { + local dir="$1" + local use_sudo="$2" + if [ "$use_sudo" = "true" ]; then + sudo install -m 755 "${TMP}/${BINARY}" "${dir}/${BINARY}" + else + install -m 755 "${TMP}/${BINARY}" "${dir}/${BINARY}" + fi +} + +LOCAL_BIN="$HOME/.openclaw/skills/bin" +mkdir -p "$LOCAL_BIN" 2>/dev/null || true + +if install_bin "$LOCAL_BIN" "false" 2>/dev/null; then + INSTALL_DIR="$LOCAL_BIN" + # Check if it's on PATH + case ":$PATH:" in + *":${LOCAL_BIN}:"*) ;; + *) + echo "" + echo "Installed to ${LOCAL_BIN}/${BINARY}" + echo "Add the following to your shell profile to use it:" + echo " export PATH=\"\$HOME/.openclaw/skills/bin:\$PATH\"" + ;; + esac +else + SYSTEM_BIN="/usr/local/bin" + install_bin "$SYSTEM_BIN" "true" + INSTALL_DIR="$SYSTEM_BIN" +fi + +echo "" +echo "gate-cli ${VERSION} installed to ${INSTALL_DIR}/${BINARY}" +echo "Run: gate-cli --version" \ No newline at end of file diff --git a/agents/market_making_expert/skills/gate_exchange_marketanalysis/SKILL.md b/agents/market_making_expert/skills/gate_exchange_marketanalysis/SKILL.md new file mode 100644 index 00000000..216cfe59 --- /dev/null +++ b/agents/market_making_expert/skills/gate_exchange_marketanalysis/SKILL.md @@ -0,0 +1,75 @@ +--- +name: gate_exchange_marketanalysis +description: Gate.io perpetual market analysis framework — trend, volatility, volume + profile, order book, and funding rate read before deploying or adjusting any Gate + MM strategy. +when_to_use: Before deploying, resuming, or tuning any market-making strategy on gate_io_perpetual. + Run this analysis on the target pair to determine regime, optimal spread profile, + fill timing, and whether conditions favor symmetric or asymmetric quoting. +created: '2026-08-18T03:19:30Z' +source: agent:market_making_expert +--- + +## Gate Exchange Market Analysis — Framework + +### Step 1: Trend & Momentum +Pull 14-day hourly candles. Compute: +- 14-day range and % move +- 7-day and 1-day range +- Structure: higher highs / lower lows / ranging +- Flag: is today the first meaningful rejection? Or continuation? + +Regime labels: +- `volatile_trending`: >20% in 7d, expanding candle bodies, surging volume +- `volatile_ranging`: wide swings but no sustained direction +- `quiet_ranging`: <5% in 7d, small bodies, low volume — ideal for tight symmetric MM + +### Step 2: Volatility (ATR estimate from hourly candles) +- Quiet regime: candle bodies < $3–5, volume < 10K/hr +- Active regime: candle bodies $30–90, volume 50K+/hr +- Breakout regime: bodies $80–100+, volume 100K+/hr +→ Breakout/active = use asymmetric spreads; quiet = symmetric spreads viable + +### Step 3: Volume Profile +Identify the 3–5 highest-volume candles over 14 days: +- Volume spike at low = capitulation (buy-side opportunity) +- Volume spike at breakout = momentum confirmation +- Volume spike at new high = potential distribution +Current volume vs. prior quiet hours: if still >3× quiet baseline, regime is still hot. + +### Step 4: Order Book +Fetch snapshot. Key reads: +- Best bid/ask spread: if 1 tick → highly competitive, queue position matters +- Ask depth L1: if <0.1 contracts → paper thin, sell L1 fills instantly on any sweep +- Bid walls: large qty at a level = defended support, safe for buy-side quoting +- Ask walls: large qty at a level = resistance, good TP target zone + +MM implications: +- Thin ask → place sell L1 at least 2–3 ticks behind best ask for queue safety +- Fat bid wall → buy L1 can be placed just above it to compete for queue + +### Step 5: Funding Rate +- <+0.01%: neutral, no bias +- +0.01–0.03%: mild long premium — slight inventory lean to long is fine +- >+0.05%: crowded long — widen sell spreads or pause sells +- Negative: short squeeze risk — tighten buys, widen sells + +### Step 6: Regime → Spread Profile Decision +| Regime | Buy spreads | Sell spreads | Skew | Notes | +|---|---|---|---|---| +| quiet_ranging | 0.02/0.08/0.20% | 0.02/0.08/0.20% | 1.0 | Symmetric | +| volatile_ranging | 0.03/0.10/0.25% | 0.05/0.15/0.35% | 1.5 | Mild asymmetry | +| volatile_trending | 0.02/0.08/0.20% | 0.04/0.16/0.40% | 1.8–2.0 | Sell side 2× wider | + +### Step 7: Gate.io Rebate Check +- Confirm VIP tier has negative maker fee (target: −0.015%) +- take_profit=0.0003 (0.03%) = breakeven without rebate +- With rebate: +0.06% gross per round-trip +- Circuit breaker: if net PnL per fill is negative after first 20 fills → pause and check tier + +### Output +After running this framework, state: +- regime: