AlgoHandControl MT5 EAs by chat
Developer docs

EA Spec Protocol (ESP) 0.1

One JSON document per Expert Advisor build (keyed by the file's sha256) that says what the terminal exposes and what people know about every input. Every semantic field carries provenance and a trust level; the AlgoHand control server derives what an assistant may read, change and restart from trust, never from free text.

WhyDocument shapeTrustPermissionsThree ways inAPISchema (JSON)

Why a spec, not a document

A compiled EA shows the terminal its inputs, defaults and nothing else. Whether MaxSpread is safe to change to 50, whether LotSizingMethod=5 means "low risk", whether a restart with open positions loses the basket: that knowledge lives in manuals, in the author's source code and in customers' heads. ESP is the contract that carries it into the control server in a form a machine can check: the terminal is ground truth for structure, the spec only adds meaning, and each meaning knows who asserted it.

Document shape

{
  "esp_version": "0.1",
  "ea": { "name": "Gridkeeper", "file_name": "gridkeeper_v3.ex5", "sha256": "…", "ea_version": "3.2",
          "author": "…", "platform": "MT5", "docs_url": null, "category": "grid", "description": null },
  "generated_by": { "path": "author_source | client_manual | discovery_auto | catalog | test_run",
                    "tool": "algohand-prompt-v1 | onboarding-ui | agent-discovery", "timestamp": "2026-09-08T12:00:00Z" },
  "restart_behavior": { "recovers_open_positions": true, "recovery_mechanism": "reads positions by magic number on init",
                        "safe_to_restart_with_open_positions": true, "notes": null,
                        "provenance": { "source": "author_source", "trust": "author" } },
  "parameters": [
    { "key": "MaxSpread", "type": "double",
      "terminal": { "default": 2.0, "min": null, "max": null, "current": null, "enum_labels": null },
      "label": "Max spread", "meaning": "Maximum allowed spread in points before entries are skipped.", "unit": "points",
      "risk_relevant": false, "safe_range": { "min": 0.5, "max": 5.0 }, "requires_restart": true, "hidden": false,
      "provenance": { "terminal_block": "discovery",
                      "meaning":    { "source": "author_source", "trust": "author" },
                      "safe_range": { "source": "client_manual", "trust": "client", "entered_by": "u_…", "timestamp": "…" } } }
  ],
  "presets":    [ { "name": "conservative", "label": "Cautious", "values": { "RiskPercent": 0.5 },
                    "provenance": { "source": "author_source", "trust": "author" } } ],
  "signatures": [ { "who": "author@example.com", "role": "author", "asserted": ["parameters.MaxSpread.meaning"], "at": "…" } ]
}

terminal.* is always filled by AlgoHand's own discovery on a terminal, never taken from an upload. MT5 inputs carry no hard min/max, so those are usually null; safe_range is the human-asserted range. Types: bool, int, double, string, csv, enum. Uploads that fail the schema are refused with the failing paths.

Trust levels and provenance

trustsource
nonefield empty or unknown (terminal block only)
inferreda guess from the input's name and default (AlgoHand's heuristics or AI); shown as a guess, never a permission
cliententered by the customer in onboarding (chat, dashboard or API) and signed by them
authorproduced from the source code by the author's own AI through the published prompt, or written by the author in the studio
verifiedconfirmed by a supervised run on a demo terminal: the reconciler observed the effect
curatedreviewed and signed off by AlgoHand staff

Trust only goes up: an upload never overwrites a field asserted by a stronger source. An uploader cannot claim more than their role (a client key asserts client at most). signatures[] records who asserted what and when; a customer who signs a safe range has taken that decision for their own account.

Permissions, derived at request time

conditioneffective permission
no spec, or an input with a terminal block onlyread-only: status, reporting, pause/stop, remove from chart
meaning at client+ and not risk_relevantwritable within the known range
risk_relevant: truewritable only with a safe_range at author+, or a range the client signed for themselves; writes are clamped to it
enum without option labelsread-only until the labels are supplied
requires_restart with open positionsallowed only when safe_to_restart_with_open_positions is asserted at author+
bool switches, comment strings, lot size of a non-risk inputwritable at inferred trust (whitelist v1, server-side, versioned)

Presets are offered only at client trust or better: the customer's own or the author's. AlgoHand never generates or recommends risk presets.

Three ways in, one file

Every upload is cross-checked row by row against what the terminal showed: an input the terminal does not have, a wrong type or a wrong default is rejected per row, the rest is accepted; inputs the upload does not mention keep their terminal block. The build's sha256 must match a file the agent found on the customer's VPS or in the studio. A new build gets a new hash: unchanged inputs keep their semantics, only new or changed ones are asked again.

API

callwhat
GET /v1/esp/schemathe JSON Schema (draft 2020-12), public; also esp.schema.json
GET /v1/esp/promptalgohand-prompt-v1: what an author pastes into their own AI together with the source
POST /v1/esp/validate {"spec": …}public validation → {valid, errors[{path, message}]}
GET /v1/eas/{ea_id}/specESP view of a catalog EA with the derived permissions
GET /v1/clients/{id}/eas/{custom_id}/specthe customer's spec (stored, else derived from onboarding), permissions, progress
POST /v1/clients/{id}/eas/{custom_id}/spec {"spec": …, "note": …}upload or update: schema → sha256 → discovery cross-check → trust merge → signature → policy

Errors: 422 SPEC_INVALID (schema, with paths), 409 SPEC_SHA_MISMATCH (another build), 422 EA_NOT_DISCOVERED. Full reference: API docs, section 10g of the README.