dydx-agent-gateway 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. dydx_agent_gateway-0.3.0/.agents/skills/dydx-gateway/SKILL.md +61 -0
  2. dydx_agent_gateway-0.3.0/.agents/skills/dydx-gateway/references/data-gotchas.md +33 -0
  3. dydx_agent_gateway-0.3.0/.github/workflows/release.yml +26 -0
  4. dydx_agent_gateway-0.3.0/.github/workflows/tests.yml +27 -0
  5. dydx_agent_gateway-0.3.0/.gitignore +13 -0
  6. dydx_agent_gateway-0.3.0/CHANGELOG.md +122 -0
  7. dydx_agent_gateway-0.3.0/LICENSE +21 -0
  8. dydx_agent_gateway-0.3.0/PKG-INFO +134 -0
  9. dydx_agent_gateway-0.3.0/README.md +104 -0
  10. dydx_agent_gateway-0.3.0/alerts.py +68 -0
  11. dydx_agent_gateway-0.3.0/backup.sh +26 -0
  12. dydx_agent_gateway-0.3.0/demos/demo1_funding_watch.py +38 -0
  13. dydx_agent_gateway-0.3.0/demos/demo2_trader_check.py +41 -0
  14. dydx_agent_gateway-0.3.0/deploy-public.md +55 -0
  15. dydx_agent_gateway-0.3.0/dydx_mcp/__init__.py +1 -0
  16. dydx_agent_gateway-0.3.0/dydx_mcp/analytics.py +130 -0
  17. dydx_agent_gateway-0.3.0/dydx_mcp/api.py +142 -0
  18. dydx_agent_gateway-0.3.0/dydx_mcp/detectors.py +144 -0
  19. dydx_agent_gateway-0.3.0/dydx_mcp/paths.py +20 -0
  20. dydx_agent_gateway-0.3.0/dydx_mcp/pnl_engine.py +115 -0
  21. dydx_agent_gateway-0.3.0/dydx_mcp/registry.py +82 -0
  22. dydx_agent_gateway-0.3.0/dydx_mcp/server.py +775 -0
  23. dydx_agent_gateway-0.3.0/dydx_mcp/signer.py +278 -0
  24. dydx_agent_gateway-0.3.0/dydx_mcp/ta_ext.py +115 -0
  25. dydx_agent_gateway-0.3.0/examples/README.md +52 -0
  26. dydx_agent_gateway-0.3.0/examples/alerts.env.example +9 -0
  27. dydx_agent_gateway-0.3.0/examples/claude-desktop/config-http.json +9 -0
  28. dydx_agent_gateway-0.3.0/examples/claude-desktop/config.json +13 -0
  29. dydx_agent_gateway-0.3.0/examples/codex/config.toml +11 -0
  30. dydx_agent_gateway-0.3.0/examples/cursor/mcp.json +8 -0
  31. dydx_agent_gateway-0.3.0/examples/python-agent.py +57 -0
  32. dydx_agent_gateway-0.3.0/examples/tool-output.md +456 -0
  33. dydx_agent_gateway-0.3.0/examples/webhook-receiver.py +35 -0
  34. dydx_agent_gateway-0.3.0/http_server.py +16 -0
  35. dydx_agent_gateway-0.3.0/leaderboard.py +78 -0
  36. dydx_agent_gateway-0.3.0/pyproject.toml +46 -0
  37. dydx_agent_gateway-0.3.0/reports/data-quality-2026-08.md +28 -0
  38. dydx_agent_gateway-0.3.0/reports/digest-2026-08-24.md +49 -0
  39. dydx_agent_gateway-0.3.0/reports/qa-logic.md +194 -0
  40. dydx_agent_gateway-0.3.0/reports/qa-report.md +85 -0
  41. dydx_agent_gateway-0.3.0/reports/qa-v0.2.4-live.md +120 -0
  42. dydx_agent_gateway-0.3.0/reports/qa-v0.3.0-live.md +50 -0
  43. dydx_agent_gateway-0.3.0/scanner.py +168 -0
  44. dydx_agent_gateway-0.3.0/server.json +26 -0
  45. dydx_agent_gateway-0.3.0/tests/conftest.py +8 -0
  46. dydx_agent_gateway-0.3.0/tests/test_a2_price_precision.py +151 -0
  47. dydx_agent_gateway-0.3.0/tests/test_analytics.py +85 -0
  48. dydx_agent_gateway-0.3.0/tests/test_api.py +177 -0
  49. dydx_agent_gateway-0.3.0/tests/test_detectors.py +122 -0
  50. dydx_agent_gateway-0.3.0/tests/test_extras.py +109 -0
  51. dydx_agent_gateway-0.3.0/tests/test_online.py +100 -0
  52. dydx_agent_gateway-0.3.0/tests/test_paths_registry.py +51 -0
  53. dydx_agent_gateway-0.3.0/tests/test_regressions.py +113 -0
  54. dydx_agent_gateway-0.3.0/tests/test_scanner.py +57 -0
  55. dydx_agent_gateway-0.3.0/tests/test_server.py +117 -0
  56. dydx_agent_gateway-0.3.0/tests/test_signer.py +58 -0
  57. dydx_agent_gateway-0.3.0/tests/test_suite.py +89 -0
  58. dydx_agent_gateway-0.3.0/tests/test_ta_ext.py +193 -0
  59. dydx_agent_gateway-0.3.0/tests/test_ta_ext_reference.py +224 -0
  60. dydx_agent_gateway-0.3.0/tests/test_v030_tools.py +279 -0
  61. dydx_agent_gateway-0.3.0/watchdog.py +60 -0
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: dydx-gateway
3
+ description: "Use when the user asks about anything dYdX — markets, prices, funding, OI, volumes, perps — or mentions a perp trader address to vet (equity, PnL curve, day-winrate, maxDD, farmer flag), funding/OI anomalies, liquidation cascades, leaderboards, or wants TA and ATR-based stop plans. Provides dYdX v4 perps analytics via a local read-only MCP gateway: market data, funding heatmap, verified trader PnL, leaderboards, OI and liquidation-cascade anomaly detection."
4
+ when_to_use: "Use for any dYdX questions — markets, prices, funding, OI, volumes; anomalies (OI spikes without price movement, liquidation cascades, extreme funding, trader equity jumps); trader analysis by address (equity, PnL curve, day-winrate, maxDD, farmer flag) before copy-trading; leaderboard and onchain trader screening; TA and ATR-based stop plans. Trigger words: dYdX, perps, funding, OI anomaly, trader PnL, vet this trader, liquidation cascade."
5
+ metadata:
6
+ version: "0.3.0"
7
+ agent:
8
+ requires:
9
+ bins: ["python3"]
10
+ ---
11
+
12
+ # dYdX Agent Gateway (local MCP server)
13
+
14
+ The gateway is deployed on this host, endpoint **http://127.0.0.1:8901/mcp**
15
+ (streamable HTTP, systemd unit `dydx-mcp.service`; check with
16
+ `systemctl is-active dydx-mcp`). The code lives at the repository root
17
+ of https://github.com/alekskram/dydx-agent-gateway
18
+ (the skill's source is `.agents/skills/dydx-gateway/`; after edits,
19
+ copy it to `~/.zcode/skills/dydx-gateway/`). If the gateway is not
20
+ running, start it per the repo README Install section
21
+ (`uvx --from git+https://github.com/alekskram/dydx-agent-gateway
22
+ dydx-agent-gateway --http --port 8901`).
23
+
24
+ Background data: the block scanner (`dydx-scanner`, the address registry
25
+ keeps growing), detectors every 5 min (`dydx-detectors.timer`),
26
+ leaderboard every 6 h (`dydx-leaderboard.timer`), watchdog report on the
27
+ 1st of each month.
28
+
29
+ ## MCP tools (22)
30
+
31
+ Data: `list_markets`, `market_detail`, `candles`, `recent_trades`, `height`
32
+ · Analytics: `funding_heatmap(min_oi_usd)`, `historical_funding(limit≤500)`,
33
+ `market_ta`, `suggest_stops`, `trader_profile`,
34
+ `trader_pnl_stats(limit≤5000)`, `fills_review`, `raw_fills(limit≤200)`,
35
+ `cvd(trades_limit)`, `correlation(ticker_a, ticker_b)`
36
+ · Discovery: `market_digest` (one-call briefing — start here),
37
+ `leaderboard`, `discover_traders`, `list_traders`, `registry_stats`,
38
+ `latest_events`, `usage_stats`
39
+
40
+ ## Quick path without an MCP client
41
+
42
+ ```bash
43
+ cd <repo root> && python -c "
44
+ import sys; sys.path.insert(0,'.')
45
+ from dydx_mcp import server as s
46
+ import json; print(json.dumps(s.market_digest(), indent=1, default=str)[:800])"
47
+ ```
48
+
49
+ Full-blown connections (stdio / Claude Desktop, Codex, Cursor configs):
50
+ `examples/` in the repo.
51
+
52
+ ## Important data caveats
53
+
54
+ Read `references/data-gotchas.md` (5 documented indexer-API gotchas:
55
+ candle ordering, netTransfers, priceChange24H, subticksPerTick, no
56
+ liquidation feed). Rule of thumb: funding without an OI ≥ $100k filter
57
+ is noise.
58
+
59
+ ## Where to look next
60
+
61
+ - Reports: `reports/` (monthly data-quality watchdog, digests)
@@ -0,0 +1,33 @@
1
+ # dYdX indexer API — documented gotchas (found by our watchdog)
2
+
3
+ Five non-obvious behaviors of indexer.dydx.trade that make naive
4
+ clients lie (each caught on live data and covered by gateway tests):
5
+
6
+ 1. **Candles and historical-pnl arrive newest-first** (newest entries
7
+ first). A consumer expecting chronology inverts the sign of
8
+ ΔOI/Δprice and the TA trend. Our API layer normalizes this (sorting
9
+ by startedAt). Example damage: a signal reading "OI shrank −8.9%"
10
+ was in fact +9.7% growth.
11
+
12
+ 2. **`netTransfers` in historical-pnl is a flow for the period between
13
+ points, NOT cumulative.** A running sum is required. Without it, the
14
+ deposit-adjusted drawdown of a reference market maker looks like
15
+ 79.5% instead of the real 11.9% (a 67 pp phantom gap).
16
+
17
+ 3. **`priceChange24H` in perpetualMarkets does not match the actual 24h
18
+ price change** (verified against ETH/BTC candles). Compute it
19
+ yourself: close[-1]/close[-25] over 1H candles.
20
+
21
+ 4. **The price subticks field is called `subticksPerTick`** (not
22
+ subticksPerBase): price_subticks = price / tickSize × subticksPerTick.
23
+ For ETH (tick 0.1, spt 100000) — price×10^6.
24
+
25
+ 5. **There is no public liquidations feed** (several candidate paths
26
+ return 404). Cascades are caught by a candle signature: |Δprice|↑
27
+ together with OI↓ (2 stages: fresh_2h on 5-min candles,
28
+ confirmed_6h on hourly).
29
+
30
+ Plus: **extreme funding on markets with OI < $100k is noise**
31
+ (example: CRO "+2967% annualized" at $4.5k OI). Always filter by OI.
32
+
33
+ Current version: reports/data-quality-2026-08.md in the gateway repo.
@@ -0,0 +1,26 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
12
+ contents: write
13
+ steps:
14
+ - uses: actions/checkout@v5
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: "3.13"
18
+ - run: pip install build twine
19
+ - run: python -m build
20
+ - run: python -m twine check dist/*
21
+ - uses: pypa/gh-action-pypi-publish@release/v1
22
+ - name: GitHub Release
23
+ uses: softprops/action-gh-release@v2
24
+ with:
25
+ files: dist/*
26
+ generate_release_notes: true
@@ -0,0 +1,27 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ offline:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python: ["3.11", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v5
16
+ - uses: actions/setup-python@v6
17
+ with:
18
+ python-version: ${{ matrix.python }}
19
+ - run: pip install -e ".[dev]"
20
+ - name: Run tests
21
+ run: |
22
+ pytest tests/ -q --cov=dydx_mcp --tb=short > pytest_output.txt 2>&1 || FAILED=1
23
+ grep -E "^(FAILED|ERROR)|Error|error" pytest_output.txt | head -25 | while IFS= read -r line; do
24
+ echo "::error::${line:0:250}"
25
+ done
26
+ tail -40 pytest_output.txt
27
+ exit ${FAILED:-0}
@@ -0,0 +1,13 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ data/*.sqlite
5
+ data/*.sqlite-wal
6
+ data/*.sqlite-shm
7
+ alerts.env
8
+ *.log
9
+ .coverage
10
+
11
+ # internal documents (not for publication)
12
+ PLAN.md
13
+ dist/
@@ -0,0 +1,122 @@
1
+ # Changelog
2
+
3
+ ## v0.3.0 (2026-09-03) — analyst pack
4
+ - 4 new tools: `historical_funding` (raw 1h funding-rate series with
5
+ annualized rate = rate*24*365, ticker-guard), `cvd` (cumulative volume
6
+ delta from the trades tape: buy/sell by side, current CVD + series over
7
+ the window), `correlation` (Pearson r over log-returns of two tickers'
8
+ candles + beta(a|b)), `raw_fills` (raw fills of a trader for own
9
+ execution analysis; addresses from discover_traders/leaderboard).
10
+ - Enrichments: `market_ta` + MACD(12,26,9) + VWAP(20, typical price x
11
+ volume) + realized_vol (annualized at candle resolution); `market_detail`
12
+ + basis_pct (mark deviation from oracle); `trader_pnl_stats` +
13
+ sortino_like_daily (downside deviation) next to the sharpe-like metric.
14
+ - Fix: api historical_funding used a non-working query path (404) —
15
+ switched to the path form /historicalFunding/{ticker}.
16
+ - Fix (live QA): correlation aligned the two candle series by index
17
+ tail; candle feeds are trade-driven and can differ by a bar, which
18
+ shifted one series and collapsed r (BTC/ETH 1h: 0.853 -> 0.033).
19
+ Now joined on startedAt (inner join). raw_fills prints
20
+ self-consistent price/size/usd_notional (6 significant digits).
21
+ - Tests: +29 invariant (ta_ext) and regression tests per tool (mocked,
22
+ incl. ticker-guard cases) + shift-bug regression; plus an independent
23
+ numpy reference cross-check on randomized data
24
+ (tests/test_ta_ext_reference.py, tol 1e-9; author ≠ ta_ext author —
25
+ owner requirement).
26
+ - Version bump 0.2.5 -> 0.3.0 (pyproject, FastMCP server, server.json);
27
+ numpy added to dev extras (reference cross-check; runtime stays stdlib).
28
+
29
+ ## v0.2.5 (2026-09-02) — logical-QA fixes (review/43, findings A1-A4)
30
+ - A2 (bug, Medium): adaptive price precision in `suggest_stops` /
31
+ `market_ta` via `_fmt_price` — at least 6 significant digits (never fewer
32
+ decimals than before), so level geometry (SL < entry < TP) and ATR
33
+ multipliers hold in the printed JSON fields for sub-cent assets
34
+ (DOGE entry now prints 0.08148 with SL 0.08073, not 0.08 vs 0.0807).
35
+ - A3 (semantics, Medium): `trader_pnl_stats` adds `max_drawdown_usd` (depth
36
+ of the same worst drawdown in USD) and `dd_pct_unreliable: true` when the
37
+ deposit-adjusted curve's running peak at the worst drawdown is near zero
38
+ (< $1 or < 1% of current equity) — the peak-relative
39
+ `max_drawdown_pct` exceeds 100% there and misleads (t3 case: 2711.54%);
40
+ thresholds per Researcher (review).
41
+ - A1/A4 (docs): README "Data notes" — indicators recompute per candle
42
+ window; `nextFundingRate` is an exchange preview, `volume24H` a rolling
43
+ window.
44
+ - Version bump 0.2.4 -> 0.2.5 (pyproject, FastMCP server, server.json).
45
+
46
+ ## v0.2.4 (2026-09-02) — pre-publication hardening (review)
47
+ - Crash fixes (found in the review internal review, each with a regression test):
48
+ pnl_engine.compute no longer raises on None equity/totalPnl/netTransfers
49
+ fields (API nulls) or on a single history point (ZeroDivisionError in the
50
+ summary line); market_digest/leaderboard summaries no longer raise
51
+ TypeError on NULL pnl_window (rows from accounts with 'no pnl history').
52
+ - api.markets() now filters FINAL_SETTLEMENT (settled) markets: 197 of 296
53
+ listings were dead but still leaked zero-volume rows into list_markets and
54
+ stale nonzero funding rates into funding_heatmap/detectors. Live markets
55
+ only (status == ACTIVE) by default.
56
+ - server.json rebuilt against the official MCP Registry server schema
57
+ (2025-12-11): 0 validation errors — description <= 100 chars, name
58
+ `io.github.ventures/dydx-agent-gateway` placeholder (GitHub org pending),
59
+ registryType + transport{stdio} in the package, repository block added,
60
+ $schema URL fixed (old raw.githubusercontent URL was 404).
61
+ - Demo numbers in README dated "as of 2026-08" (kept, not scrubbed,
62
+ by design decision).
63
+ - Version bump 0.2.3 -> 0.2.4 (pyproject, FastMCP server, SKILL.md).
64
+
65
+ ## v0.2.1 (2026-08-25) — QA pass: full review and testing
66
+ - Tests: pytest structure (49 offline + 5 online, online marker), dydx_mcp
67
+ coverage 75% (up from ~8% of functions); dev extras [dev]; CI workflow
68
+ ready.
69
+ - 7 bugs found and fixed with regression tests: short keys in key_from_hex;
70
+ event dedup never expired (ts format); prune over-deletion; market_ta
71
+ crash on flat candles; equity_jumps connection leak; BOUNDARY DUPLICATES
72
+ in PnL pagination (live test); isError semantics for invalid tickers
73
+ (ValueError).
74
+ - Chaos 4/4: restore drill, scanner SIGKILL idempotency (+23 = +23), load
75
+ test 20 clients / 0 errors, state survives force-reinstall.
76
+ - QA report: reports/qa-report.md
77
+
78
+ ## v0.1.1 (2026-08-25)
79
+ - `trader_pnl_stats(limit)` — agents get up to 5000 history points
80
+ (~7 months); default 1000 (~42 days, fast).
81
+ - `market_digest` — one-call briefing: detector events + funding extremes
82
+ + leaderboard top.
83
+ - `usage_stats` + tool-call accounting (middleware → sqlite) — traction
84
+ metrics for grant KPIs (calls/24h/7d, top tools).
85
+ - `watchdog.py` + dydx-watchdog timer (1st of the month, 09:00) — the
86
+ data-quality report is generated automatically.
87
+ - README: dydx-backup unit in the automation table, deploy-public.md link.
88
+ - fastmcp banner disabled (stdio/HTTP).
89
+
90
+ ## v0.1.0 (2026-08-24)
91
+ - 19 MCP tools: market data, analytics, leaderboard, events, screener.
92
+ - PnL engine: deposit-adjusted curve, day-winrate, maxDD, identity check
93
+ (residual $0.00 on live data), history pagination up to 5000 points.
94
+ - Block scanner → address registry (bech32 BIP-173, idempotent).
95
+ - Detectors: funding_extreme, oi_spike_no_price, liq_cascade_signature
96
+ (validated on history: 47 signature hours/7d), equity_jump.
97
+ - EIP-712 signer (Order, ApiCredentials; 12/12 selftests).
98
+ - pip package (pyproject, console entry point), examples for Claude
99
+ Desktop/Codex/Cursor, skill, HTTP+stdio transports.
100
+ - systemd: 5 units + hardening; WAL-safe backup (restore verified).
101
+ - Tests: suite 15/15; 5 indexer API gotchas found and fixed.
102
+
103
+ ## v0.2.0 (2026-08-25) — skill and MCP standards
104
+ - Skill rewritten to skill-creator standards: EN description with triggers
105
+ in the visible zone (~250 chars), when_to_use (detailed triggers),
106
+ metadata.agent.requires.bins; source of truth — .agents/skills/ in the
107
+ repo (discoverable root), self-contained (references/data-gotchas.md),
108
+ sync with ~/.zcode/skills documented.
109
+ - MCP compliance: tool annotations (readOnlyHint/destructiveHint/
110
+ idempotentHint — 21 tools), server instructions (strategy for the
111
+ agent), /health endpoint (custom_route).
112
+ - recent_traders → list_traders (SEP-986 distinctness from recent_trades).
113
+ - server.json for the official MCP registry (reverse-DNS, draft).
114
+ - deploy-public.md: origin/host validation, OAuth 2.1 note.
115
+
116
+ ## v0.2.3 — analytics-only release
117
+ - Trading tools (place_order / cancel_all / my_positions) removed from the
118
+ MCP server by design decision: the public gateway is read-only analytics,
119
+ holds no keys, signs nothing. Signer stays as a library module (offline
120
+ selftest 12/12), unwired to any tool.
121
+ - demo3_order_consent.py removed; docs (EN/RU README, examples, skill)
122
+ updated; tool count 21 -> 18.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dydx-agent-gateway contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.5
2
+ Name: dydx-agent-gateway
3
+ Version: 0.3.0
4
+ Summary: MCP gateway for AI agents to dYdX v4: market data, funding heatmap, TA, verified trader analytics (deposit-adjusted PnL), leaderboards, anomaly & liquidation-cascade detectors. Analytics-only: no trading tools, no keys.
5
+ Project-URL: Homepage, https://github.com/alekskram/dydx-agent-gateway
6
+ Project-URL: Repository, https://github.com/alekskram/dydx-agent-gateway
7
+ Project-URL: Issues, https://github.com/alekskram/dydx-agent-gateway/issues
8
+ Project-URL: Changelog, https://github.com/alekskram/dydx-agent-gateway/blob/master/CHANGELOG.md
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,analytics,defi,dydx,mcp,perpetuals,trading
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Office/Business :: Financial :: Investment
19
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: ecdsa>=0.18
22
+ Requires-Dist: fastmcp>=3.0
23
+ Requires-Dist: pycryptodome>=3.20
24
+ Provides-Extra: dev
25
+ Requires-Dist: numpy>=1.26; (python_version >= '3.11') and extra == 'dev'
26
+ Requires-Dist: pip-audit; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # dYdX Agent Gateway
32
+
33
+ [![tests](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml/badge.svg)](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml)
34
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org)
35
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
36
+
37
+ One MCP server that gives any AI agent analytics access to dYdX v4: market data, funding analytics, verified trader PnL, leaderboards, anomaly detection. Read-only and keyless — the gateway holds no keys and cannot move funds.
38
+
39
+ ## Install
40
+
41
+ **Claude Code:**
42
+ ```bash
43
+ claude mcp add dydx -- uvx --from git+https://github.com/alekskram/dydx-agent-gateway dydx-agent-gateway
44
+ ```
45
+
46
+ **Cursor / any mcp.json:**
47
+ ```json
48
+ {"mcpServers": {"dydx": {
49
+ "command": "uvx",
50
+ "args": ["--from", "git+https://github.com/alekskram/dydx-agent-gateway", "dydx-agent-gateway"]}}}
51
+ ```
52
+
53
+ **Codex** (`~/.codex/config.toml`):
54
+ ```toml
55
+ [mcp_servers.dydx]
56
+ command = "uvx"
57
+ args = ["--from", "git+https://github.com/alekskram/dydx-agent-gateway", "dydx-agent-gateway"]
58
+ ```
59
+
60
+ **ZCode** — register the MCP server and copy the agent skill (all copy-paste):
61
+ ```bash
62
+ # 1) start the gateway (keep it running)
63
+ uvx --from git+https://github.com/alekskram/dydx-agent-gateway dydx-agent-gateway --http --port 8901 &
64
+
65
+ # 2) register it (merges into ~/.zcode/cli/config.json; workspace .zcode/config.json works too)
66
+ python3 - <<'PY'
67
+ import json, os
68
+ p = os.path.expanduser("~/.zcode/cli/config.json")
69
+ os.makedirs(os.path.dirname(p), exist_ok=True)
70
+ cfg = json.load(open(p)) if os.path.exists(p) else {}
71
+ cfg.setdefault("mcp", {}).setdefault("servers", {})["dydx"] = {
72
+ "type": "http", "url": "http://127.0.0.1:8901/mcp"}
73
+ json.dump(cfg, open(p, "w"), indent=2)
74
+ print("dydx MCP server registered:", p)
75
+ PY
76
+
77
+ # 3) copy the agent skill (tool guide + data gotchas)
78
+ git clone -q --depth 1 https://github.com/alekskram/dydx-agent-gateway /tmp/dag
79
+ cp -r /tmp/dag/.agents/skills/dydx-gateway ~/.zcode/skills/ && rm -rf /tmp/dag
80
+ echo "ZCode setup done — restart your session and call any dydx tool"
81
+ ```
82
+
83
+ **Plain Python:**
84
+ ```bash
85
+ pip install git+https://github.com/alekskram/dydx-agent-gateway
86
+ python -c "from dydx_mcp import server; import json; print(json.dumps(server.market_digest(), default=str)[:400])"
87
+ ```
88
+
89
+ **Hosted (streamable HTTP):** `dydx-agent-gateway --http --port 8901`, then any client:
90
+ ```json
91
+ {"mcpServers": {"dydx": {"type": "http", "url": "http://host:8901/mcp"}}}
92
+ ```
93
+
94
+ Requires Python ≥ 3.11. Deps (`fastmcp`, `pycryptodome`, `ecdsa`) install automatically. See `examples/` for ready-made configs and a working autonomous agent script.
95
+
96
+ ## Tools (22 — read-only, keyless)
97
+
98
+ | Group | Tools |
99
+ |---|---|
100
+ | Market data | `list_markets`, `market_detail`, `candles`, `recent_trades`, `height`, `historical_funding` |
101
+ | Analytics | `funding_heatmap`, `market_ta`, `suggest_stops`, `cvd`, `correlation` |
102
+ | Traders | `trader_profile`, `trader_pnl_stats`, `fills_review`, `raw_fills` |
103
+ | Discovery | `discover_traders`, `leaderboard`, `list_traders`, `registry_stats` |
104
+ | Signals | `latest_events` (funding extremes, OI spikes, liquidation cascades, equity jumps) |
105
+ | Briefing | `market_digest` — one call: events + funding + leaderboard top. **Start here.** |
106
+
107
+ Real outputs of every tool: [`examples/tool-output.md`](examples/tool-output.md).
108
+
109
+ ## What makes it different
110
+
111
+ - **Verified trader PnL.** `trader_pnl_stats` reconciles the identity `equity-Δ = Δpnl + ΣnetTransfers` on every account — residual ≠ 0 means the numbers lie. Live-checked on real accounts to $0.0000 (see `reports/qa-logic.md`). Deposit-adjusted maxDD, day-winrate, sharpe-like.
112
+ - **Anomaly detectors, not dashboards.** Funding extremes, OI spikes without price, equity jumps, and a liquidation-cascade signature (|Δprice|↑ + OI↓) — the patterns that matter before they're charts. Live catches in `reports/`.
113
+ - **Analyst pack.** Funding-rate history, CVD, cross-market correlation, raw fills for execution analysis; TA enrichments MACD/VWAP/realized vol; sortino-like downside risk.
114
+ - **Data-quality discipline.** Five documented indexer API gotchas (`.agents/skills/dydx-gateway/references/data-gotchas.md`) that silently corrupt naive analytics. 129 tests, CI on 3.11/3.13.
115
+
116
+ ## Data notes
117
+
118
+ Indicators are computed over the current candle window and change with every new bar. `nextFundingRate` is the exchange's live preview and is recomputed continuously; `volume24H` is a rolling window. Two calls moments apart legitimately differ.
119
+
120
+ ## Safety model
121
+
122
+ All tools are read-only and keyless. The gateway signs nothing and holds no credentials. An offline-tested EIP-712 signer remains in `dydx_mcp/signer.py` as a library for anyone building their own execution layer — it is wired to no MCP tool.
123
+
124
+ ## FAQ
125
+
126
+ - **Does it trade?** No. Analytics only, by design.
127
+ - **API keys?** None. Everything runs on public indexer endpoints.
128
+ - **Rate limits?** Public endpoints, no auth; a 60s markets cache keeps you polite.
129
+ - **How do I verify a trader before copying them?** `trader_profile` → `trader_pnl_stats` → `fills_review` — check the identity residual and maker/taker mix first.
130
+
131
+
132
+ ## License
133
+
134
+ MIT. Not affiliated with dYdX Trading Inc.
@@ -0,0 +1,104 @@
1
+ # dYdX Agent Gateway
2
+
3
+ [![tests](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml/badge.svg)](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml)
4
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
6
+
7
+ One MCP server that gives any AI agent analytics access to dYdX v4: market data, funding analytics, verified trader PnL, leaderboards, anomaly detection. Read-only and keyless — the gateway holds no keys and cannot move funds.
8
+
9
+ ## Install
10
+
11
+ **Claude Code:**
12
+ ```bash
13
+ claude mcp add dydx -- uvx --from git+https://github.com/alekskram/dydx-agent-gateway dydx-agent-gateway
14
+ ```
15
+
16
+ **Cursor / any mcp.json:**
17
+ ```json
18
+ {"mcpServers": {"dydx": {
19
+ "command": "uvx",
20
+ "args": ["--from", "git+https://github.com/alekskram/dydx-agent-gateway", "dydx-agent-gateway"]}}}
21
+ ```
22
+
23
+ **Codex** (`~/.codex/config.toml`):
24
+ ```toml
25
+ [mcp_servers.dydx]
26
+ command = "uvx"
27
+ args = ["--from", "git+https://github.com/alekskram/dydx-agent-gateway", "dydx-agent-gateway"]
28
+ ```
29
+
30
+ **ZCode** — register the MCP server and copy the agent skill (all copy-paste):
31
+ ```bash
32
+ # 1) start the gateway (keep it running)
33
+ uvx --from git+https://github.com/alekskram/dydx-agent-gateway dydx-agent-gateway --http --port 8901 &
34
+
35
+ # 2) register it (merges into ~/.zcode/cli/config.json; workspace .zcode/config.json works too)
36
+ python3 - <<'PY'
37
+ import json, os
38
+ p = os.path.expanduser("~/.zcode/cli/config.json")
39
+ os.makedirs(os.path.dirname(p), exist_ok=True)
40
+ cfg = json.load(open(p)) if os.path.exists(p) else {}
41
+ cfg.setdefault("mcp", {}).setdefault("servers", {})["dydx"] = {
42
+ "type": "http", "url": "http://127.0.0.1:8901/mcp"}
43
+ json.dump(cfg, open(p, "w"), indent=2)
44
+ print("dydx MCP server registered:", p)
45
+ PY
46
+
47
+ # 3) copy the agent skill (tool guide + data gotchas)
48
+ git clone -q --depth 1 https://github.com/alekskram/dydx-agent-gateway /tmp/dag
49
+ cp -r /tmp/dag/.agents/skills/dydx-gateway ~/.zcode/skills/ && rm -rf /tmp/dag
50
+ echo "ZCode setup done — restart your session and call any dydx tool"
51
+ ```
52
+
53
+ **Plain Python:**
54
+ ```bash
55
+ pip install git+https://github.com/alekskram/dydx-agent-gateway
56
+ python -c "from dydx_mcp import server; import json; print(json.dumps(server.market_digest(), default=str)[:400])"
57
+ ```
58
+
59
+ **Hosted (streamable HTTP):** `dydx-agent-gateway --http --port 8901`, then any client:
60
+ ```json
61
+ {"mcpServers": {"dydx": {"type": "http", "url": "http://host:8901/mcp"}}}
62
+ ```
63
+
64
+ Requires Python ≥ 3.11. Deps (`fastmcp`, `pycryptodome`, `ecdsa`) install automatically. See `examples/` for ready-made configs and a working autonomous agent script.
65
+
66
+ ## Tools (22 — read-only, keyless)
67
+
68
+ | Group | Tools |
69
+ |---|---|
70
+ | Market data | `list_markets`, `market_detail`, `candles`, `recent_trades`, `height`, `historical_funding` |
71
+ | Analytics | `funding_heatmap`, `market_ta`, `suggest_stops`, `cvd`, `correlation` |
72
+ | Traders | `trader_profile`, `trader_pnl_stats`, `fills_review`, `raw_fills` |
73
+ | Discovery | `discover_traders`, `leaderboard`, `list_traders`, `registry_stats` |
74
+ | Signals | `latest_events` (funding extremes, OI spikes, liquidation cascades, equity jumps) |
75
+ | Briefing | `market_digest` — one call: events + funding + leaderboard top. **Start here.** |
76
+
77
+ Real outputs of every tool: [`examples/tool-output.md`](examples/tool-output.md).
78
+
79
+ ## What makes it different
80
+
81
+ - **Verified trader PnL.** `trader_pnl_stats` reconciles the identity `equity-Δ = Δpnl + ΣnetTransfers` on every account — residual ≠ 0 means the numbers lie. Live-checked on real accounts to $0.0000 (see `reports/qa-logic.md`). Deposit-adjusted maxDD, day-winrate, sharpe-like.
82
+ - **Anomaly detectors, not dashboards.** Funding extremes, OI spikes without price, equity jumps, and a liquidation-cascade signature (|Δprice|↑ + OI↓) — the patterns that matter before they're charts. Live catches in `reports/`.
83
+ - **Analyst pack.** Funding-rate history, CVD, cross-market correlation, raw fills for execution analysis; TA enrichments MACD/VWAP/realized vol; sortino-like downside risk.
84
+ - **Data-quality discipline.** Five documented indexer API gotchas (`.agents/skills/dydx-gateway/references/data-gotchas.md`) that silently corrupt naive analytics. 129 tests, CI on 3.11/3.13.
85
+
86
+ ## Data notes
87
+
88
+ Indicators are computed over the current candle window and change with every new bar. `nextFundingRate` is the exchange's live preview and is recomputed continuously; `volume24H` is a rolling window. Two calls moments apart legitimately differ.
89
+
90
+ ## Safety model
91
+
92
+ All tools are read-only and keyless. The gateway signs nothing and holds no credentials. An offline-tested EIP-712 signer remains in `dydx_mcp/signer.py` as a library for anyone building their own execution layer — it is wired to no MCP tool.
93
+
94
+ ## FAQ
95
+
96
+ - **Does it trade?** No. Analytics only, by design.
97
+ - **API keys?** None. Everything runs on public indexer endpoints.
98
+ - **Rate limits?** Public endpoints, no auth; a 60s markets cache keeps you polite.
99
+ - **How do I verify a trader before copying them?** `trader_profile` → `trader_pnl_stats` → `fills_review` — check the identity residual and maker/taker mix first.
100
+
101
+
102
+ ## License
103
+
104
+ MIT. Not affiliated with dYdX Trading Inc.
@@ -0,0 +1,68 @@
1
+ """Alerts: publish unpublished events to Telegram + registered webhooks.
2
+
3
+ Env: DYDX_TG_BOT_TOKEN + DYDX_TG_CHAT_ID (Telegram),
4
+ DYDX_WEBHOOKS="https://a/hook,https://b/hook" (comma-separated).
5
+ Without env set, events stay queued (published=0) — nothing is lost.
6
+ """
7
+ import json
8
+ import os
9
+ import sys
10
+ import urllib.request
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, str(Path(__file__).parent))
14
+ from dydx_mcp import analytics # noqa: E402
15
+
16
+
17
+ def tg_send(text: str) -> bool:
18
+ tok, chat = os.environ.get("DYDX_TG_BOT_TOKEN"), os.environ.get("DYDX_TG_CHAT_ID")
19
+ if not (tok and chat):
20
+ return False
21
+ req = urllib.request.Request(
22
+ f"https://api.telegram.org/bot{tok}/sendMessage",
23
+ data=json.dumps({"chat_id": chat, "text": text[:4000]}).encode(),
24
+ headers={"Content-Type": "application/json"})
25
+ try:
26
+ with urllib.request.urlopen(req, timeout=10) as r:
27
+ return r.status == 200
28
+ except Exception: # noqa: BLE001
29
+ return False
30
+
31
+
32
+ def webhook_send(url: str, payload: dict) -> bool:
33
+ req = urllib.request.Request(url, data=json.dumps(payload).encode(),
34
+ headers={"Content-Type": "application/json"})
35
+ try:
36
+ with urllib.request.urlopen(req, timeout=10) as r:
37
+ return 200 <= r.status < 300
38
+ except Exception: # noqa: BLE001
39
+ return False
40
+
41
+
42
+ def publish_all() -> int:
43
+ hooks = [u for u in os.environ.get("DYDX_WEBHOOKS", "").split(",") if u]
44
+ con = analytics.con()
45
+ rows = con.execute("SELECT * FROM events WHERE published=0 ORDER BY id").fetchall()
46
+ n = 0
47
+ for r in rows:
48
+ p = json.loads(r["payload"])
49
+ text = f"⚠️ {r['kind']} {r['subject']}: {json.dumps(p, ensure_ascii=False)[:300]}"
50
+ tg_configured = bool(os.environ.get("DYDX_TG_BOT_TOKEN")
51
+ and os.environ.get("DYDX_TG_CHAT_ID"))
52
+ tg_ok = tg_send(text) if tg_configured else True
53
+ hooks_ok = True
54
+ for u in hooks:
55
+ if not webhook_send(u, {"kind": r["kind"], "subject": r["subject"],
56
+ "payload": p, "ts": r["ts"]}):
57
+ hooks_ok = False
58
+ delivered = (tg_ok and hooks_ok) and (tg_configured or hooks)
59
+ if delivered:
60
+ con.execute("UPDATE events SET published=1 WHERE id=?", (r["id"],))
61
+ n += 1
62
+ con.commit()
63
+ con.close()
64
+ return n
65
+
66
+
67
+ if __name__ == "__main__":
68
+ print("published:", publish_all())
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # Consistent daily backup: sqlite .backup snapshots (WAL-safe) + reports.
3
+ set -e
4
+ BASE=/root/ventures/dydx-grant/agent-gateway
5
+ PY="$BASE/.venv/bin/python"
6
+ S="$(mktemp -d)"
7
+ mkdir -p "$S/reports"
8
+
9
+ "$PY" - "$BASE" "$S" <<'EOF'
10
+ import sqlite3, sys
11
+ from pathlib import Path
12
+ base, stage = Path(sys.argv[1]), Path(sys.argv[2])
13
+ for name in ("registry.sqlite", "analytics.sqlite"):
14
+ src, dst = base / "data" / name, stage / name
15
+ s = sqlite3.connect(f"file:{src}?mode=ro", uri=True)
16
+ d = sqlite3.connect(dst)
17
+ s.backup(d)
18
+ d.close(); s.close()
19
+ print("snapshot:", name)
20
+ EOF
21
+
22
+ cp -r "$BASE/reports/." "$S/reports/"
23
+ tar czf "/root/backups/dydx-gateway-$(date +%F).tar.gz" -C "$S" .
24
+ rm -rf "$S"
25
+ find /root/backups -name "dydx-gateway-*.tar.gz" -mtime +30 -delete
26
+ echo "backup done"