# Personal Trading Agent (Web App) — Development Plan and Implementation Guide

## 0. How to read this report

Every claim below is tagged:

- **[FACT]** — directly confirmed against a primary source, cited.
- **[INFERENCE]** — a reasonable conclusion drawn from facts, not itself stated by a source.
- **[UNCERTAIN]** — could not be confirmed; treated as a working assumption only.
- **[OPEN QUESTION]** — needs an answer from the requester before implementation can proceed safely.

---

## 1. Source verification (done before any design work)

### 1.1 `https://mcp.openmarket.xyz/llms.txt` — **[FACT]**

Fetched directly. The page documents a real, live MCP ("Model Context Protocol") server at `https://mcp.openmarket.xyz/`, described as "the OpenMarket chart MCP server," using Streamable HTTP transport with browser-based sign-in. Key documented behavior, quoted/paraphrased from the source:

- **Connecting**: The user signs in once in a browser and chooses an access level — *read only*, *read and control charts*, or (where offered) *trading*. "Alerts and watchlists" is on by default. Shell-capable agents (Claude Code, Codex, Cursor) can add the connector via client-specific config; chat apps (claude.ai, Claude Desktop, ChatGPT) require the user to add the URL in settings. A token-based setup exists for scripts/CI, with tokens generated on an "OpenMarket Agents" page; tokens must stay in local client config, never pasted into chat.
- **Tool groups** exposed by the server:
  - `mcp:chart` — chart control: `chart_workspace_select` (open a specific chart by ID), `chart_create` (temporary scratch charts), symbol/timeframe/indicator changes.
  - `mcp:read` — `chart_read` (numbers on the open chart), plus `metric_get`, `points`, `markets` for market data without an open tab.
  - `mcp:alerts` — alert and watchlist management (plan-based limits).
  - `mcp:trade` — orders are placed **by the user's browser tab**, within limits the user sets there; the user must "arm" the agent in the tab first; writes should use idempotency keys.
- **Workflow the server itself prescribes**: select the named chart with `chart_workspace_select`, confirm with `chart_status`, read data with `chart_refresh`, then propose one small change at a time, wait for approval, apply it, and report the result. A chart is only "data-bearing" once status is `"loaded"`.
- **Limits**: data rate and candle history depend on the user's plan; unknown symbols can be rejected with suggested alternatives.

This is the authoritative, load-bearing source for the integration layer of this plan. All architecture recommendations for "interfacing with chart v7mi0CgA" are built on this documented tool surface.

**Important correction to the brief's framing [INFERENCE]**: the source shows that OpenMarket's own design keeps live order placement under the *user's browser tab and user-set limits*, with the agent only proposing changes that a human (or an explicitly "armed" session) approves. A "fully autonomous" trading mode as the brief requests is technically possible (the user can pre-arm the tab and raise limits), but it is OpenMarket's documented design choice, not this report's, that trading execution is gated through the browser and through user-controlled arming/limits — this materially shapes any "autonomous" feature design and should not be engineered around.

### 1.2 Chart ID `v7mi0CgA` — **[UNCERTAIN]**

The llms.txt page confirms that charts are referenced by an ID and opened via `chart_workspace_select`, so an ID shaped like `v7mi0CgA` is consistent with the documented mechanism. However:

- This ID could not be independently resolved to a specific symbol/timeframe/indicator set from the public `llms.txt` page alone — that requires an authenticated session (sign-in choosing an access level) that this task does not have and should not attempt to obtain, since browser sign-in is explicitly the **requester's/user's** account action, not something to fetch on their behalf without consent.
- **Treat `v7mi0CgA` as a placeholder/user-settable configuration value** (an environment variable, e.g. `OPENMARKET_CHART_ID`), not a hard-coded constant, until the user confirms what chart it opens and under which OpenMarket account/plan.

### 1.3 "Jev skills for algorithmic trading" — **[UNCERTAIN / likely not what the brief implies]**

Web search found a single piece of secondary coverage (a marketing/blog article syndicated across ~10 locale mirrors of the same source, not a primary vendor page) describing **"Jev"** as a non-generative decision model released by a company called "TypeSafe AI," founder named Diogo Almeida, released September 15 (year not confirmed), used for calibrated trading decisions (regime/toxicity/strategy classification) in 70–500ms, with a cited example of a Monad market-making bot querying it every 300ms. No official TypeSafe AI site, documentation, GitHub repo, or API reference was found or fetched — the claims above come only from that one syndicated article and are **not independently verified**.

- No evidence was found of a product, package, or API literally named **"Jev skills"**, nor of any relationship between "Jev" and OpenMarket/mcp.openmarket.xyz.
- **[OPEN QUESTION]**: Is "Jev skills" (a) the "Jev" decision model described above, under a different name/product tier, (b) an unrelated proprietary or internal tool the requester already has access to, or (c) a feature the requester wants built from scratch using an LLM/rules engine? This determines whether "Jev" is an external dependency to integrate (needing an API key/endpoint from the requester) or a component this plan should design in-house.

Given this, the architecture below treats "algorithmic trading skills" as a **pluggable strategy module** — generic enough to wrap a real "Jev" API once the requester clarifies its interface, but not dependent on unverified specifics.

---

## 2. Architecture overview

```
┌─────────────────────────────────────────────────────────────────┐
│                         Web App (Frontend)                        │
│  React/Next.js SPA — Dashboard, Chart panel, Manual trade panel,  │
│  Strategy config, Autonomy on/off switch, Audit/activity log      │
└───────────────┬─────────────────────────────────┬─────────────────┘
                │ REST/WebSocket                   │ (embed or deep link)
┌───────────────▼─────────────────────┐   ┌─────────▼─────────────────┐
│           Backend API                │   │  OpenMarket chart tab      │
│  (Node/Python) — orchestrates:       │   │  (user's own browser       │
│  - Auth & session                    │   │   session, "armed" by the  │
│  - MCP client → mcp.openmarket.xyz   │◄──┤   user for mcp:trade)      │
│  - Strategy engine (rules + "Jev")   │   └────────────────────────────┘
│  - Order intent log / idempotency    │
│  - Risk limits enforcement           │
└───────┬─────────────────┬────────────┘
        │                 │
┌───────▼──────┐   ┌──────▼───────────┐
│ Data store    │   │ Scheduler/Agent  │
│ (Postgres):    │   │ loop (autonomous │
│ trades, config,│   │ mode) — polls     │
│ audit log      │   │ chart_read, calls │
└────────────────┘   │ strategy, proposes│
                      │ orders            │
                      └───────────────────┘
```

### 2.1 Components

1. **Frontend web app** — the UI the brief requires: chart view, manual trade controls, autonomy toggle, strategy parameters, live activity/audit feed.
2. **Backend orchestrator** — a single service that:
   - Holds the MCP client connection to `mcp.openmarket.xyz` (per §1.1 tool groups).
   - Exposes its own REST/WebSocket API to the frontend (never exposes the OpenMarket token to the browser).
   - Hosts the **strategy engine** (rules-based + optional "Jev"-style model call, pending §1.3).
   - Enforces **risk limits** server-side (max position size, max daily loss, cooldowns) independent of whatever limits exist in the OpenMarket tab.
3. **Scheduler / agent loop** — only active in autonomous mode; runs on a fixed interval (not sub-second — see §4 on latency reality) to call `chart_refresh`/`chart_read`, run the strategy, and submit a proposed order.
4. **Audit log / data store** — every decision (manual or autonomous), every call to `mcp:trade`, every strategy input/output, stored with timestamps and idempotency keys, per the OpenMarket server's own idempotency requirement.
5. **The OpenMarket browser tab itself** — per §1.1, this is **not replaceable** by the backend; it is the place where the human arms trading and where OpenMarket enforces its own limits. The web app should guide the user to open/arm it, and should treat its "armed" state as a precondition it polls/displays, not something it can set unilaterally.

---

## 3. Tech stack recommendations

| Layer | Recommendation | Why |
|---|---|---|
| Frontend | Next.js (React) + TypeScript, Tailwind | Fast iteration, SSR for the dashboard, good WebSocket support for live chart/order updates |
| Chart rendering in-app | Embed/iframe the OpenMarket chart tab where OpenMarket's product allows it, or mirror `chart_read` data into a lightweight library (e.g. `lightweight-charts`) for a read-only preview | The authoritative, trade-armed chart lives in the OpenMarket tab per §1.1 — duplicating it risks desync; a read-only mirror avoids that while still giving a nice UI |
| Backend | Node.js (TypeScript) with an MCP client SDK, or Python (FastAPI) if the strategy/ML stack is Python-heavy | MCP client libraries exist in both ecosystems; pick based on where "Jev" (once clarified) is easiest to call |
| MCP transport | Streamable HTTP, per `llms.txt` | This is what the server documents — no alternative transport was offered |
| Database | Postgres | Durable audit trail for every trade decision/idempotency key, required for compliance and debugging |
| Scheduler | A simple cron-style job (e.g. `node-cron` / APScheduler) inside the backend, interval configurable (e.g. 30–300s) | Matches realistic MCP/API polling cadence; avoids false "HFT" promises (see §4) |
| Auth | Standard session auth for the web app; OpenMarket's own browser sign-in/token flow kept separate and never proxied through the web app's own user accounts | Per `llms.txt`, tokens "should stay in local client configuration, never in a chat" — by extension, never in a web app's general-purpose database either, without explicit secret handling |
| Secrets | A secrets manager (e.g. Doppler, Vault, or cloud KMS) for the OpenMarket token and any "Jev" API key | Standard practice; these are high-value credentials |

---

## 4. Integration with `mcp.openmarket.xyz` and chart `v7mi0CgA`

### 4.1 Setup sequence (derived directly from the `llms.txt` workflow, §1.1)

1. User signs in once via browser, selecting an access level (read-only / read+control / trading). For this agent, **read+control at minimum**, **trading** if autonomous execution is wanted.
2. Backend adds the MCP connector using the documented Streamable HTTP endpoint, or (for the server-side/scheduled agent loop) uses a **token** generated on OpenMarket's "Agents" page, stored only in server-side config/secrets — never sent to or rendered in the frontend.
3. On startup, call `chart_workspace_select` with the configured chart ID (`OPENMARKET_CHART_ID`, defaulting to `v7mi0CgA` only once the user confirms that is correct — see §1.2).
4. Call `chart_status`; do not treat any chart as data-bearing until status is `"loaded"`.
5. Call `chart_refresh` / `chart_read` to pull current numbers for the strategy engine.
6. For any trade: compose one proposed order, apply backend risk checks, then submit via `mcp:trade` tools with an **idempotency key**; remember that OpenMarket requires the user to have "armed" the browser tab, and that execution ultimately happens through that tab within user-set limits — the web app's "fully autonomous" mode means *the backend decides and submits without per-trade human click-through*, not that it bypasses OpenMarket's own arming/limits gate.

### 4.2 Example code (Node/TypeScript, illustrative — adjust to the actual MCP client SDK and tool schemas once accessed with real credentials)

```ts
// openmarket-client.ts
import { MCPClient } from "@modelcontextprotocol/sdk/client"; // illustrative import

export class OpenMarketClient {
  private client: MCPClient;

  constructor(private token: string, private chartId: string) {
    this.client = new MCPClient({
      url: "https://mcp.openmarket.xyz/",
      transport: "streamable-http",
      auth: { token: this.token }, // server-side only, never exposed to frontend
    });
  }

  async openChart() {
    await this.client.callTool("chart_workspace_select", { chartId: this.chartId });
    const status = await this.client.callTool("chart_status", {});
    if (status.state !== "loaded") {
      throw new Error(`Chart ${this.chartId} not loaded: ${status.state}`);
    }
  }

  async readMarket() {
    await this.client.callTool("chart_refresh", {});
    return this.client.callTool("chart_read", {});
  }

  async proposeOrder(order: { symbol: string; side: "buy" | "sell"; qty: number }, idempotencyKey: string) {
    // Requires the user's browser tab to be "armed" for trading (OpenMarket-side precondition).
    return this.client.callTool("order_place", { ...order, idempotencyKey });
  }
}
```

```ts
// agent-loop.ts — autonomous mode scheduler
import { OpenMarketClient } from "./openmarket-client";
import { runStrategy } from "./strategy";
import { withinRiskLimits } from "./risk";
import { v4 as uuid } from "uuid";

export async function autonomousTick(client: OpenMarketClient, enabled: boolean) {
  if (!enabled) return; // autonomy toggle, controlled from the web app
  const marketData = await client.readMarket();
  const decision = await runStrategy(marketData); // rules engine and/or external "Jev"-style model
  if (decision.action !== "hold" && withinRiskLimits(decision)) {
    await client.proposeOrder(decision.order, uuid());
    // log decision + order to Postgres audit table
  }
}
// Call autonomousTick on a scheduled interval (e.g. every 30–300s), not sub-second —
// see §4.3 on realistic latency for an MCP/browser-mediated integration.
```

```ts
// strategy.ts — pluggable strategy module (keeps "Jev" swappable once its real interface is known)
export interface StrategyInput { candles: unknown; indicators: unknown; }
export interface StrategyDecision { action: "buy" | "sell" | "hold"; order?: { symbol: string; side: "buy"|"sell"; qty: number }; }

export async function runStrategy(input: StrategyInput): Promise<StrategyDecision> {
  // Placeholder rules-based baseline. Replace/augment with a call to the
  // requester's actual "Jev"-equivalent decision API once its endpoint,
  // auth, and input/output schema are confirmed (see Report §1.3, open question).
  return { action: "hold" };
}
```

### 4.3 Latency reality check — **[FACT + INFERENCE]**

The one source found on "Jev" claims 70–500ms *model* decision latency used inside a 300ms *block-level* loop for a Monad market maker [UNCERTAIN, unverified secondary source]. That is unrelated to this agent's actual bottleneck: trading here goes through a **browser-tab-mediated MCP server** with user-set limits and an arming step (§1.1, FACT). **[INFERENCE]**: realistic polling/decision cadence for this architecture is seconds, not milliseconds — design the UI, scheduler, and user expectations around that, not around HFT-style framing implied by the brief or by the "Jev" article.

---

## 5. Features

### 5.1 Manual trade controls
- Symbol/side/quantity/order-type form in the web app, backed by `chart_read`/`metric_get` for live quote display.
- Every manual submission goes through the same backend risk-limit check and idempotency-key flow as autonomous orders, and is logged identically.
- Clear UI state showing whether the OpenMarket tab is currently "armed" for trading (the web app should query/display this, not assume it).

### 5.2 Autonomous agentic trading
- Toggle in the UI (`autonomyEnabled`), server-enforced, not just a frontend flag.
- Configurable strategy parameters (symbols, position sizing, max daily loss, allowed hours).
- Scheduler runs `autonomousTick` per §4.2 at a configurable interval.
- Kill switch: a single control that immediately sets `autonomyEnabled = false` server-side and stops the scheduler — must be reachable even if the frontend is down (e.g. a backend admin endpoint).

### 5.3 Strategy / "Jev" integration
- Built as an injectable module (`runStrategy`) so that once the requester clarifies what "Jev skills" refers to (§1.3), it can be wired in as an external API call without changing the rest of the system.

---

## 6. Open questions for the requester

1. What chart does ID `v7mi0CgA` actually refer to (symbol, timeframe), and under which OpenMarket account/plan was it created? This cannot be resolved from the public `llms.txt` page alone.
2. What is "Jev skills" concretely — a specific product/API the requester already has access to (please share its endpoint/docs), or a feature to be designed from scratch? The only public information found describes an unrelated/unverified third-party model called "Jev," not a confirmed "skills" product.
3. Does the requester have (or want to create) an OpenMarket account with trading-level access, given that live order execution is gated through that account's browser tab per the server's own documented design?

These are flagged as open questions in the report rather than guessed at, per the "distinguish facts from unanswered questions" requirement; they do not block delivery of this architecture/plan, which is designed to be answerable once those details arrive.

---

## 7. Sources

- `https://mcp.openmarket.xyz/llms.txt` — fetched directly, primary source for the MCP server's connection flow, tool groups, and trading-gating design (§1.1, §4.1).
- Youmind.com syndicated article, "How to Use Jev to Build a 24/7 HFT Trading System" (multiple locale mirrors of the same article) — secondary, unverified source for the only "Jev" information found (§1.3, §4.3). No primary TypeSafe AI documentation was located.
- General web search for `mcp.openmarket.xyz` / "OpenMarket chart agent trading" returned no additional independent sources beyond the `llms.txt` page itself.
