Skip to main content

xAlmanac Upload API

API v1

Push MT5 backtest and optimization results into your xTriel profile from an external agent. Each upload appears in xAlmanac as a fully-parsed preset — metrics, balance curve, inputs, and a Tester-settings panel — with the .set downloadable from there.

xTriel can't read files on your machine. Your local agent reads the MT5 report .htm and the .set, then POSTs their contents to this endpoint.

1 · Authentication

Uploads use your per-user Ingest Token — the same xti_… token the Reporter EA uses. No separate credential.

  1. Sign in → ProfileConnect your EA.
  2. Generate / copy your Ingest Token (shown once — store it safely).
  3. Send it as a Bearer header on every request:
Authorization: Bearer xti_xxxxxxxxxxxxxxxxxxxxxxxx

The token resolves to your account server-side — you never send a user id or email. Regenerating it invalidates the old token for both the Reporter EA and the agent.

Plan note: xAlmanac is a paid feature — the Free plan stores 0 presets, so uploads on a Free account return ALMANAC_LIMIT. Starter stores 15, Pro 50, and Max is unlimited; every paid tier gets the same compare and export tools.

2 · Endpoint

POST https://xtriel.com/api/almanac/ingest
Authorization: Bearer xti_…
Content-Type: application/json

Body — a batch of one or more results:

{
  "presets": [
    {
      "ea": "MyExpert",            // REQUIRED — groups results under this EA
      "version": "v1",                         // optional (default "v1")
      "name": "EURUSD H1 example",          // optional display name
      "kind": "optimization",                 // optional: "backtest" | "optimization"

      "setFile": {                             // REQUIRED — the EA inputs (.set) as text
        "name": "result.set",
        "content": "InpRiskPerSetupPercent=2.0\nInpTakeProfitMode=3\n..."
      },

      "reportFile": {                          // recommended — the MT5 .htm report
        "name": "ReportTester.html",
        "contentBase64": "PGh0bWw+...",        // base64 of the report bytes
        "encoding": "utf-16le"                 // MT5 reports are often UTF-16
      },

      "tester": {                              // recommended — the Strategy Tester run config
        "expert": "MyExpert.ex5",
        "symbol": "EURUSD", "timeframe": "H1", "model": 4,
        "fromDate": "2026.06.22", "toDate": "2026.06.28",
        "deposit": 10000, "currency": "USD", "leverage": "1:100"
      },

      "results": { "netProfit": 12450, "profitFactor": 1.84, "maxDDpct": 8.7 },
      "sourceKey": "sha256-of-set-and-report"  // optional dedupe key
    }
  ]
}

Field reference

xAlmanac upload request fields
FieldReqNotes
eayesEA name (≤64). Results group under it in xAlmanac.
setFile.contentyesThe .set as UTF-8 text.
setFile.nameOriginal filename (used for the download name).
versionDefaults to "v1".
nameDisplay name for the result.
kind"backtest"/"optimization"; inferred from the .set if omitted.
reportFile.contentBase64Base64 of the MT5 .htm. Parsed in your browser for metrics + balance curve.
reportFile.encodinge.g. utf-16le, utf-8. If omitted, xAlmanac sniffs the BOM when parsing in your browser.
reportHtmlB64Shorthand alias for reportFile.contentBase64.
testerRun config shown in the Tester panel. Keys: expert, symbol, timeframe/period, model, fromDate, toDate, deposit, currency, leverage, optimization, optimizationCriterion, executionMode, spread, forwardMode. Unknown keys dropped.
resultsHeadline metrics (object). Stored as sent; xAlmanac fills missing metrics from the report in your browser.
equityBalance curve [[time, balance], …] (≤5000). Usually taken from the report.
tagsArray of strings.
sourceKeyDedupe key — re-runs update instead of duplicating.
Limits report ≤ 2 MB decoded body ≤ 25 MB ≤ 50 presets/batch results ≤ 16 KB equity ≤ 5000 points

3 · Response & errors

{
  "ok": true,
  "created": [ { "artifactId": "…", "ea": "MyExpert", "version": "v1", "name": "…" } ],
  "updated": [],
  "skipped": []
}

created new · updated dedupe hit · skipped rejected (each with a reason: MISSING_EA, MISSING_SET, BAD_REPORT, REPORT_TOO_LARGE, ALMANAC_LIMIT, …). A bad item never fails the whole batch.

xAlmanac API error responses
StatusMeaning
401Missing / invalid token.
400Malformed JSON, no presets array, or >50 presets in a batch.
413Body too large.
429Too many bad-token attempts — back off ~15 min.

4 · What you get in xAlmanac

Open xAlmanac. Uploads are auto-imported on load (or via the Agent uploads button) and render like a manual import:

  • Full Detail view — net profit, profit factor, drawdown, Sharpe, balance curve.
  • Tester settings panel — Expert, Symbol, Period, Model, dates, Deposit, Currency, Leverage — with a blue Download .set button.
  • Source filter + column (Manual vs Agent) and an API badge.
  • Download report to retrieve the original .htm.

To reproduce a run in MT5: download the .set, open View → Strategy Tester, load the EA, Inputs → Load the .set, then match Symbol / Period / Modelling / date range / Deposit to the Tester-settings panel.

5 · Agent example (Python)

import base64, requests, pathlib

GATEWAY = "https://xtriel.com/api/almanac/ingest"
TOKEN   = "xti_xxxxxxxxxxxxxxxxxxxxxxxx"   # Profile -> Connect your EA

def upload_result(set_path, report_path, ea, version="v1", name="", tester=None):
    set_text   = pathlib.Path(set_path).read_text(encoding="utf-8", errors="replace")
    report_raw = pathlib.Path(report_path).read_bytes()        # raw bytes (MT5 reports often UTF-16)
    preset = {
        "ea": ea, "version": version, "name": name or pathlib.Path(report_path).stem,
        "setFile": {"name": pathlib.Path(set_path).name, "content": set_text},
        "reportFile": {
            "name": pathlib.Path(report_path).name,
            "contentBase64": base64.b64encode(report_raw).decode("ascii"),
            "encoding": "utf-16le",
        },
    }
    if tester: preset["tester"] = tester
    r = requests.post(GATEWAY, headers={"Authorization": f"Bearer {TOKEN}"},
                      json={"presets": [preset]}, timeout=30)
    r.raise_for_status()
    return r.json()

print(upload_result(
    "myexpert.set", "report.htm",
    ea="MyExpert", name="EURUSD H1 example",
    tester={"expert": "MyExpert.ex5", "symbol": "EURUSD",
            "timeframe": "H1", "model": 4, "fromDate": "2026.06.22",
            "toDate": "2026.06.28", "deposit": 10000, "currency": "USD",
            "leverage": "1:100"}))

curl

curl -sS -X POST https://xtriel.com/api/almanac/ingest \
  -H "Authorization: Bearer $XTRIEL_INGEST_TOKEN" \
  -H "Content-Type: application/json" \
  --data @batch.json

6 · Deploy the upload agent

Run the agent on the machine that can read your MT5 files, or on a VPS where you sync Strategy Tester exports. Keep the ingest token out of code — pass it as an environment variable.

  1. Create a small Python environment:
    python3 -m venv .venv
    . .venv/bin/activate
    pip install requests
  2. Store the token outside the script:
    export XTRIEL_INGEST_TOKEN="xti_xxxxxxxxxxxxxxxxxxxxxxxx"
  3. Run the uploader against your exported files:
    python upload_xalmanac.py

7 · Troubleshooting

  • 401 — copy a fresh Ingest Token from Profile → Connect your EA and update your environment variable.
  • ALMANAC_LIMIT — choose a paid tier or remove old results before uploading again. Starter stores 15 presets, Pro 50, and Max is unlimited.
  • BAD_REPORT — re-export the report from MT5 Strategy Tester and preserve its original bytes before base64 encoding.
  • REPORT_TOO_LARGE — keep the decoded report at 2 MB or less.
  • Missing metrics — include the MT5 report; xAlmanac fills many gaps from it when you open the result.
Upload your "10 good results" as 10 entries in presets (one batch). Re-running with the same .set + report updates the existing result instead of duplicating. · Open xAlmanac →