A practical guide for transitioning your trading bot from eToro's demo sandbox to the real trading API — safety checks, key differences, and best practices.
Paper trading proves your signal logic, order sequencing, and state machine; production proves your discipline. Moving a bot from eToro’s virtual environment to real execution is not a find-and-replace on a URL—it is a controlled rollout: separate credentials, different execution paths, stricter risk controls, and observability you can trust when money moves. This guide highlights the differences that matter and shows how to structure configuration so you can switch environments without duplicating your strategy code.
The public API shares one base URL: https://public-api.etoro.com/api/v1/. What changes is the path and the key environment. Demo execution lives under paths that include demo (for example POST /trading/execution/demo/market-open-orders/by-amount), while live trading uses the non-demo execution routes (for example POST /trading/execution/market-open-orders/by-amount). Portfolio and P/L discovery follow the same split: demo under /trading/info/demo/..., real under /trading/info/real/portfolio, /trading/info/real/pnl, and related endpoints.
Your User Key is issued per environment (Virtual vs Real). A key that works for demo portfolio endpoints must not be assumed to work for live trading—store ETORO_ENV alongside secrets and validate on startup.
Integrations may use OAuth (Authorization: Bearer ...) or manual keys (x-api-key + x-user-key). The switching logic is the same: production traffic should use production-issued tokens or keys, rotated on a schedule and never logged. Whichever method you use, send a unique x-request-id (UUID) on every request so platform logs and your application logs can be joined during an incident.
Centralize base URL and execution path prefixes so strategy code only calls openMarketByAmount(payload) and does not embed /demo/ scattered across files.
import { randomUUID } from "node:crypto";
const BASE = "https://public-api.etoro.com/api/v1";
/** @type {{ env: "demo" | "real"; apiKey: string; userKey: string }} */
const cfg = {
env: process.env.ETORO_ENV === "real" ? "real" : "demo",
apiKey: process.env.ETORO_API_KEY,
userKey: process.env.ETORO_USER_KEY,
};
function authHeaders() {
return {
"x-request-id": randomUUID(),
"x-api-key": cfg.apiKey,
"x-user-key": cfg.userKey,
"content-type": "application/json",
};
}
function executionPath(kind) {
const root =
cfg.env === "demo"
? `${BASE}/trading/execution/demo`
: `${BASE}/trading/execution`;
return `${root}/${kind}`;
}
export async function openMarketByAmount(body) {
const url = executionPath("market-open-orders/by-amount");
const res = await fetch(url, {
method: "POST",
headers: authHeaders(),
body: JSON.stringify(body),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`openMarket ${res.status}: ${text}`);
}
return res.json();
}
Trading bodies use PascalCase fields such as InstrumentID, IsBuy, Leverage, and Amount—keep serializers shared between environments so you do not drift.
Reconciliation loops should hit the same “side” of the API as execution. Demo positions and P/L come from GET /trading/info/demo/portfolio and GET /trading/info/demo/pnl; live accounts use GET /trading/info/real/portfolio and GET /trading/info/real/pnl. The snippet below keeps polling logic identical while swapping only the path—pair it with exponential backoff when you receive 429.
function tradingInfoPath(resource) {
if (cfg.env === "demo") {
return resource === "pnl"
? `${BASE}/trading/info/demo/pnl`
: `${BASE}/trading/info/demo/portfolio`;
}
return resource === "pnl"
? `${BASE}/trading/info/real/pnl`
: `${BASE}/trading/info/real/portfolio`;
}
export async function fetchPortfolioSnapshot() {
const res = await fetch(tradingInfoPath("portfolio"), {
headers: authHeaders(),
});
if (res.status === 429) throw new Error("rate_limited");
if (!res.ok) throw new Error(`portfolio ${res.status}`);
return res.json();
}
Position sizing: cap Amount and AmountInUnits with config that is stricter in production than in demo—many incidents are correct logic with wrong magnitude.
Rate limiting: backoff on 429 and avoid tight loops hitting execution or portfolio endpoints; use GET /trading/info/real/portfolio (or demo equivalent) at a sane interval, not every tick.
Error handling: treat network errors, 5xx, and partial fills as first-class states; never assume fetch success means a fully working order—parse the response body and reconcile open orders and positions.
Staged rollout: run production keys against read-only endpoints first, then enable small live notional with manual approval, then widen limits after metrics look stable.
Log structured fields: x-request-id, InstrumentID, order id, position id, and your internal strategyRunId. Alert on repeated failures, slippage spikes, or divergence between intended and reported positions.
Rollback means more than “turn off the bot”: cancel open orders with the appropriate DELETE on market or limit order endpoints, close or reduce positions via market-close-orders using positionId, and disable cron triggers in your scheduler. Keep a kill switch environment variable that your process checks before every execution call.
Migrating from demo to production is primarily about credential isolation, correct execution paths, and operational guardrails—not about rewriting your alpha. Share one codebase, parameterize environment, validate keys on startup, and treat the first week of live trading as a limited experiment with tight limits and full observability. For exact path names and body schemas, always cross-check the official API Portal before you deploy.
Was this helpful?
A step-by-step guide to building a simple trading bot using the eToro Demo Trading API.
How to programmatically search, filter, and explore eToro's instrument catalog — asset classes, exchanges, industries, and historical data.
Track positions, calculate P&L, monitor account balances, and manage your portfolio programmatically through the eToro API.
Build a fully functional algorithmic trading bot using the eToro API with position management, risk controls, and automated strategy execution.
Be the first to know when we publish new API guides, changelog entries, and developer resources.
Newsletter coming soon. We'll only email you when it launches.