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.
- dydx_agent_gateway-0.3.0/.agents/skills/dydx-gateway/SKILL.md +61 -0
- dydx_agent_gateway-0.3.0/.agents/skills/dydx-gateway/references/data-gotchas.md +33 -0
- dydx_agent_gateway-0.3.0/.github/workflows/release.yml +26 -0
- dydx_agent_gateway-0.3.0/.github/workflows/tests.yml +27 -0
- dydx_agent_gateway-0.3.0/.gitignore +13 -0
- dydx_agent_gateway-0.3.0/CHANGELOG.md +122 -0
- dydx_agent_gateway-0.3.0/LICENSE +21 -0
- dydx_agent_gateway-0.3.0/PKG-INFO +134 -0
- dydx_agent_gateway-0.3.0/README.md +104 -0
- dydx_agent_gateway-0.3.0/alerts.py +68 -0
- dydx_agent_gateway-0.3.0/backup.sh +26 -0
- dydx_agent_gateway-0.3.0/demos/demo1_funding_watch.py +38 -0
- dydx_agent_gateway-0.3.0/demos/demo2_trader_check.py +41 -0
- dydx_agent_gateway-0.3.0/deploy-public.md +55 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/__init__.py +1 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/analytics.py +130 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/api.py +142 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/detectors.py +144 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/paths.py +20 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/pnl_engine.py +115 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/registry.py +82 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/server.py +775 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/signer.py +278 -0
- dydx_agent_gateway-0.3.0/dydx_mcp/ta_ext.py +115 -0
- dydx_agent_gateway-0.3.0/examples/README.md +52 -0
- dydx_agent_gateway-0.3.0/examples/alerts.env.example +9 -0
- dydx_agent_gateway-0.3.0/examples/claude-desktop/config-http.json +9 -0
- dydx_agent_gateway-0.3.0/examples/claude-desktop/config.json +13 -0
- dydx_agent_gateway-0.3.0/examples/codex/config.toml +11 -0
- dydx_agent_gateway-0.3.0/examples/cursor/mcp.json +8 -0
- dydx_agent_gateway-0.3.0/examples/python-agent.py +57 -0
- dydx_agent_gateway-0.3.0/examples/tool-output.md +456 -0
- dydx_agent_gateway-0.3.0/examples/webhook-receiver.py +35 -0
- dydx_agent_gateway-0.3.0/http_server.py +16 -0
- dydx_agent_gateway-0.3.0/leaderboard.py +78 -0
- dydx_agent_gateway-0.3.0/pyproject.toml +46 -0
- dydx_agent_gateway-0.3.0/reports/data-quality-2026-08.md +28 -0
- dydx_agent_gateway-0.3.0/reports/digest-2026-08-24.md +49 -0
- dydx_agent_gateway-0.3.0/reports/qa-logic.md +194 -0
- dydx_agent_gateway-0.3.0/reports/qa-report.md +85 -0
- dydx_agent_gateway-0.3.0/reports/qa-v0.2.4-live.md +120 -0
- dydx_agent_gateway-0.3.0/reports/qa-v0.3.0-live.md +50 -0
- dydx_agent_gateway-0.3.0/scanner.py +168 -0
- dydx_agent_gateway-0.3.0/server.json +26 -0
- dydx_agent_gateway-0.3.0/tests/conftest.py +8 -0
- dydx_agent_gateway-0.3.0/tests/test_a2_price_precision.py +151 -0
- dydx_agent_gateway-0.3.0/tests/test_analytics.py +85 -0
- dydx_agent_gateway-0.3.0/tests/test_api.py +177 -0
- dydx_agent_gateway-0.3.0/tests/test_detectors.py +122 -0
- dydx_agent_gateway-0.3.0/tests/test_extras.py +109 -0
- dydx_agent_gateway-0.3.0/tests/test_online.py +100 -0
- dydx_agent_gateway-0.3.0/tests/test_paths_registry.py +51 -0
- dydx_agent_gateway-0.3.0/tests/test_regressions.py +113 -0
- dydx_agent_gateway-0.3.0/tests/test_scanner.py +57 -0
- dydx_agent_gateway-0.3.0/tests/test_server.py +117 -0
- dydx_agent_gateway-0.3.0/tests/test_signer.py +58 -0
- dydx_agent_gateway-0.3.0/tests/test_suite.py +89 -0
- dydx_agent_gateway-0.3.0/tests/test_ta_ext.py +193 -0
- dydx_agent_gateway-0.3.0/tests/test_ta_ext_reference.py +224 -0
- dydx_agent_gateway-0.3.0/tests/test_v030_tools.py +279 -0
- 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,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
|
+
[](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml)
|
|
34
|
+
[](https://pypi.org)
|
|
35
|
+
[](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
|
+
[](https://github.com/alekskram/dydx-agent-gateway/actions/workflows/tests.yml)
|
|
4
|
+
[](https://pypi.org)
|
|
5
|
+
[](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"
|