Skip to main content
Glama
yangjrun

gate-mcp

by yangjrun
README.md
# Gate TradFi Agent

Risk-controlled TypeScript trading agent for Gate TradFi MT5/CFD. The first release supports:

- `XAUUSD` and `NAS100`
- 1-minute entries with a locally aggregated 5-minute trend filter
- deterministic EMA pullback/breakout rules
- economic-event blackout windows
- shadow execution before live trading
- Gate OAuth with refresh-token persistence
- SQLite audit, restart recovery, reconciliation incidents, and circuit breakers
- Windows service deployment through WinSW
- a localhost-only Chinese management terminal for monitoring, configuration, OAuth, preflight, and guarded controls

The project starts in `shadow` mode. It cannot enter live orders until the shadow acceptance criteria pass and an operator explicitly unlocks live mode.

## Safety Model

- An LLM does not decide trade direction or order size.
- Write requests are never blindly retried.
- Any uncertain write creates a reconciliation incident and freezes new entries.
- Missing contract economics, stale economic-calendar data, inactive MT5 account, OAuth failure, daily loss, consecutive losses, excessive margin, excessive spread, or emergency stop blocks new orders.
- Live orders include server-side stop-loss and take-profit values.
- Live unlock is tied to a fingerprint of strategy, risk, news, and instrument configuration. Changing those settings invalidates the previous unlock.
- Shadow observations are also tied to a configuration fingerprint. Changing strategy or cost inputs requires `reset-shadow` and a new observation period.

This software is an execution framework, not investment advice. Confirm Gate TradFi eligibility, product terms, leverage, fees, and local regulatory requirements before using it.

## Requirements

- Windows 10/11 or Windows Server
- Node.js 22.x
- A Gate account with an active TradFi/MT5 account
- Network access to `https://api.gatemcp.ai` and `https://www.gate.com`

The implementation uses the MCP SDK directly. `mcporter` is not required at runtime.

## Install

```powershell
npm install
npm run check
```

Start the local host with `npm run dev`, then open `http://127.0.0.1:17840`. For automation, `set-admin-password` and `unlock-live` also accept `GATE_ADMIN_PASSWORD` and `GATE_LIVE_UNLOCK_TOKEN` environment variables so secrets do not need to appear in process command lines.

The default config is `config/agent.json`. Keep local secrets and production overrides in `config/agent.local.json` and invoke commands with `--config config/agent.local.json`.

### Network and proxies

The Agent reaches two independent hosts, and both must be reachable from the Node process:

- `api.gatemcp.ai` — the MCP exchange and info endpoints.
- `www.gate.com` — the OAuth authorization server. The SDK calls it **in process** for discovery, dynamic client registration, and token exchange, not only in the browser.

Node's global `fetch` does not honor `HTTP_PROXY`/`HTTPS_PROXY` on the supported runtime, so a proxied network needs the proxy set explicitly:

```json
{
  "mcp": {
    "proxyUrl": "http://127.0.0.1:7890"
  }
}
```

`GATE_AGENT_MCP_PROXY` overrides the file value. The proxy applies to both MCP traffic and the OAuth calls to the authorization server.

A bare `fetch failed` from `auth` or `preflight` is a connectivity problem, not a credential problem. The CLI prints the underlying cause chain (for example `fetch failed <- ECONNRESET`). Verify each host separately before debugging OAuth:

```powershell
curl.exe -s -o NUL -w "%{http_code}`n" https://api.gatemcp.ai/.well-known/oauth-authorization-server
curl.exe -s -o NUL -w "%{http_code}`n" https://www.gate.com/apiw/v2/mcp/oauth/pkce/oauth/register -X POST -H "content-type: application/json" -d "{}"
```

Add `-x http://127.0.0.1:7890` to both when testing through a proxy. The first should return 200. The second returns 400/422 when reachable; a 403 on every path means the exit IP is refused by Gate, which no client-side setting can fix — use an exit whose jurisdiction Gate serves.

## First-Time Setup

### 0. Open the management terminal

`npm run dev` now starts a persistent management host at:

```text
http://127.0.0.1:17840
```

On first visit, create a local administrator password. The password is stored as a salted scrypt hash under the configured data directory. The web host stays online when OAuth or engine preflight fails, so failures can be inspected and repaired from the UI.

The interface provides monitoring, configuration preview/application, OAuth, preflight, pause, emergency stop, incident resolution, and guarded live-mode switching. It intentionally has no manual buy/sell/order-entry screen.

### 1. Configure contract economics

Gate's public symbol list does not expose every value needed for safe position sizing. Complete these fields for both symbols in `config/agent.json` before collecting valid shadow observations:

```json
{
  "symbols": {
    "XAUUSD": {
      "contractVolume": "...",
      "minOrderVolume": "...",
      "maxOrderVolume": "...",
      "volumeStep": "...",
      "minimumStopDistance": "...",
      "commissionPerLotUsd": "..."
    }
  }
}
```

Use values shown by the authenticated Gate symbol-detail response or the Gate TradFi product interface. Do not infer contract volume or commission from price precision. If `volumeStep` is omitted, the preflight may infer it from minimum volume but intentionally marks the spec unverified.

The service refuses both shadow and live entries until every enabled symbol has verified sizing and cost inputs. This prevents meaningless shadow results based on unknown contract multipliers.

`config/agent.json` ships the values observed in a 2026-08-31 preflight against one account (`XAUUSD` contract volume 100, `NAS100` contract volume 10, min volume 0.01, max volume 10, price precision 2, commission 1 USD/lot). Contract terms, volume limits, and commission vary by account and jurisdiction, so re-run `npm run preflight` against your own account and correct any field that disagrees before collecting shadow observations.

`minimumStopDistance` is deliberately `"0"`. Gate has no minimum-stop-distance concept, and the `price_sl_level` field the gateway would otherwise fall back to is the percentage margin stop-out level, not a price distance.

### 2. Configure an operator token

Generate a random secret locally, then hash it:

```powershell
node dist/src/cli.js hash-token --token "your-long-random-secret"
```

Set the resulting SHA-256 value in `control.unlockTokenSha256`. Keep the original token outside the repository.

### 3. Configure alerts

Set `control.webhookUrl` to an HTTPS endpoint that accepts JSON POST requests. The Agent alerts on calendar failure, unknown positions, reconciliation incidents, and symbol-cycle errors.

### 4. Authorize Gate OAuth

```powershell
npm run auth
```

A Gate browser page opens. Tokens and dynamic client registration are stored under `data/oauth` by default. The long-running service never opens a browser. It may refresh an existing token; if refresh fails it stops rather than starting a new interactive flow.

### 5. Run preflight

```powershell
npm run preflight
```

Preflight validates:

- required `cex_tradfi_*` tools
- active MT5 account and positive equity
- `XAUUSD` and `NAS100` ticker/K-line availability
- contract volume, minimum/maximum volume, volume step, leverage, precision, stop distance, commission, and full trading mode
- Gate Info economic-calendar availability

`ok: true` means the Agent can run. `liveReady: true` additionally means all live contract specifications are verified.

## Shadow Mode

Start the management host and supervised Agent:

```powershell
npm run dev
```

or after building:

```powershell
npm start
```

Inspect state and performance:

```powershell
npm run status
npm run report
```

The default shadow acceptance gate is:

- at least 14 natural days
- at least 100 closed shadow trades
- net Profit Factor at least 1.20 after spread, configured commission, and slippage allowance
- maximum drawdown no more than 3%
- market-data MCP latency P95 no more than 1 second
- MCP call error rate below 1%
- no unresolved reconciliation incidents
- verified instrument economics
- unchanged shadow configuration

Historical K-lines do not contain historical bid/ask spread, so they are not treated as evidence for live acceptance. The required sample comes from forward shadow observations.

Natural days count days on which the shadow service was actually running, not merely the time between the first and last trade.

## Live Unlock

After every acceptance gate passes:

```powershell
node dist/src/cli.js unlock-live --token "your-long-random-secret" --confirm UNLOCK-LIVE
```

Then explicitly set `execution.mode` to `live` and restart the service. Both conditions are required: live config mode and a valid current unlock fingerprint.

Recommended rollout:

1. Disable `NAS100` and start `XAUUSD` at the minimum Gate volume.
2. Confirm real fills, commission, stop placement, and reconciliation.
3. Restore risk-based sizing up to the configured per-trade risk (`risk.perTradeEquityRate`).
4. Enable `NAS100` only after independent validation.

Lock live entry at any time:

```powershell
node dist/src/cli.js lock-live
```

## Controls

```powershell
node dist/src/cli.js pause
node dist/src/cli.js resume
node dist/src/cli.js emergency-stop
node dist/src/cli.js clear-emergency --confirm CLEAR-EMERGENCY
node dist/src/cli.js resolve-incident --id 123 --confirm RESOLVE-INCIDENT
node dist/src/cli.js reset-shadow --confirm RESET-SHADOW
```

`emergency-stop` immediately locks live mode. A running service closes managed shadow and live positions on its next symbol cycle. If the service is not running, close exposure through Gate first, restart for reconciliation, then clear the stop only after all positions and incidents are resolved.

Do not resolve an incident merely to make the system trade again. First compare Gate orders, positions, position history, and the local audit record.

## Strategy

The first strategy is a deterministic trend pullback:

- locally aggregate complete 1-minute K-lines into complete 5-minute bars
- 5-minute EMA20 above/below EMA50 with a matching EMA slope
- 1-minute pullback toward EMA20
- entry after the next 1-minute prior-high/prior-low breakout
- ATR-based spread filter, stop bounds, and slippage allowance
- 1.5R target by default
- maximum 15-minute holding time
- one managed position per symbol and a post-close cooldown

The Agent only uses closed K-lines for signals. TradFi K-lines do not include volume, so the strategy intentionally has no volume filter.

## Risk Defaults

Values below are what `config/agent.json` currently ships. The schema defaults in `src/config.ts` are more conservative (0.25% per trade, 2x notional); the shipped config is loosened because a single 0.01 lot of `XAUUSD` is roughly 4,400 USD of notional, which the defaults would floor to zero volume at the 1,000 USD shadow equity.

- risk per trade: 0.35% of equity (`risk.perTradeEquityRate`, schema default 0.25%)
- daily realized plus unrealized loss breaker: 1% of equity
- stop after two consecutive losing trades in the current UTC day
- total used margin after a new order: at most 10% of equity
- total notional exposure: at most 6x equity (`risk.maxTotalNotionalEquityMultiple`, schema default 2x)
- one position per symbol
- no entries within 30 minutes of instrument close
- no entries around configured US events such as FOMC, NFP, CPI, PPI, GDP, and PCE

Position volume is the minimum of the risk, margin, free-margin, notional, and instrument maximum limits, rounded down to the configured volume step.

## Windows Service

Run elevated PowerShell:

```powershell
.\scripts\install-service.ps1
```

The installer:

- runs build and tests
- installs files under `C:\ProgramData\GateTradFiAgent`
- copies the current OAuth cache
- downloads WinSW 2.12.0
- applies restricted ACLs
- installs an automatic delayed-start service under `LocalService`
- serves the UI only on `127.0.0.1:17840`

OAuth credentials are copied when they already exist, but are no longer required before installation. After the service starts, open `http://127.0.0.1:17840`, initialize the local administrator password, complete Gate OAuth, fill the contract economics, and run preflight from the management terminal.

Installed mutable configuration lives at `C:\ProgramData\GateTradFiAgent\config\agent.json`; application files remain read-only under `app`. Use the browser management terminal for ordinary configuration changes so updates are previewed, preflighted, and automatically rolled back on failure.

For a dedicated service account, PowerShell prompts securely for its password:

```powershell
$Password = Read-Host -AsSecureString
.\scripts\install-service.ps1 -ServiceUser '.\GateTradFiAgentSvc' -ServicePassword $Password
```

If using a custom account, grant it "Log on as a service" and verify the OAuth/data ACLs before starting.

Uninstall while retaining data:

```powershell
.\scripts\uninstall-service.ps1
```

Remove all local data explicitly:

```powershell
.\scripts\uninstall-service.ps1 -RemoveData
```

Control the installed service's database with `service-control.ps1`. Do not use the project-local CLI for an installed service, because the two instances use different data directories:

```powershell
.\scripts\service-control.ps1 -Command status
.\scripts\service-control.ps1 -Command emergency-stop
.\scripts\service-control.ps1 -Command clear-emergency -Confirm CLEAR-EMERGENCY
.\scripts\service-control.ps1 -Command unlock-live -Token 'your-secret' -Confirm UNLOCK-LIVE
```

## Data Layout

Development defaults:

```text
data/
├─ agent.db
├─ agent.db-shm
├─ agent.db-wal
└─ oauth/
   ├─ client.json
   ├─ tokens.json
   └─ code_verifier.txt
```

OAuth data, local config, databases, and logs are ignored by Git. Never commit them.

## Management Security

- HTTP binds only to `127.0.0.1`; non-local Host and Origin values are rejected.
- Admin passwords use scrypt with a random salt.
- Sessions use signed HttpOnly, SameSite=Strict cookies and server-side records.
- Every write API requires a same-session CSRF token.
- Pause and emergency stop remain fast; resume and other sensitive controls require password re-entry.
- Clear emergency, apply config, reset shadow data, and incident resolution additionally require explicit confirmation phrases.
- Live mode requires the admin password, the independent live unlock token, and `UNLOCK-LIVE`.
- OAuth tokens, password hashes, live unlock hashes, MCP paths, and storage paths are never returned by the configuration API.

## Development

```powershell
npm run build
npm test
npm run check
```

Tests are offline and do not access a Gate account or execute trades. Live integration is only performed through explicit `auth` and `preflight` commands.

## Known Constraints

- MCP/REST is suitable for minute-level trading, not sub-second high-frequency trading.
- Gate creates TradFi orders asynchronously and returns a task ID. The current documented MCP surface does not expose a direct task-log query or idempotency key, so uncertain writes fail closed and require reconciliation.
- K-line data contains OHLC only, not volume.
- The economic-calendar dataset currently provides event type rather than a reliable importance field. The Agent uses an explicit high-impact event-type allowlist.
- Gate product availability, symbols, leverage, and fees can vary by account and jurisdiction.