API reference

Full account report

Everything about one account in a single call — identity, curve, statement, indicators, every deal and the evaluation terms it is judged against.

Everything the platform knows about one trading account, in a single response: who it is, what it is worth, its month-by-month statement, its risk and streak indicators, its long/short split, its results per instrument and per weekday, every deal it has ever made, and the evaluation terms it is being judged against.

GET/v1/accounts/{account}/reportAvailablescope · accounts:read
curl
curl "https://api.propexecutor.com/v1/accounts/10000042/report" \
  -H "Authorization: Bearer $PFX_KEY"

Which one should you call?

This endpoint and analytics answer the same question in two different shapes. Call report when you are rendering a whole account page and want one request with nothing to stitch together — it includes the deal list and the rule terms, which analytics leaves to separate calls.

Call analytics when you are driving charts and polling: it is the lighter of the two, it carries extra series (money and deal counts split into winners and losers) and it never reads the full ledger row by row. One thing to watch if you call both: its weekday chart is Sunday-first, while this endpoint’s profitDaily is Monday-first. Each matches the contract its own clients bind to.

This is the slow one

The report reads the account’s entire trade ledger, aggregates all of it, and fetches the equity curve — deliberately, because a partial report is not a report. A profit factor computed over one page of trades is not a profit factor.

So: call it on page load, not on a timer, and not on every price tick. There is no pagination anywhere in the response. What bounds it instead is tradeHistory.deals, which is capped at 5,000 entries — totalDeals is always the true count, so you can tell when you are seeing a truncated list, and every aggregate in the object is still computed over the whole ledger rather than the capped slice.

Range

fromtimestamp
Start of the charted window, RFC 3339. Defaults to the account’s creation — this object is the account’s history, and a report that silently covered yesterday would look like an account that had barely traded. Note this differs from analytics, which defaults to the last 24 hours. Clamped forward to the account’s creation.
totimestamp
End of the charted window. Defaults to now, and is clamped to now.

The range affects balance.chart, growth.chart and the three longShort series only. Every total, indicator, table and deal covers the account’s whole life, so nothing on your statement changes because somebody looked at a different chart range.

Units, before anything else

The same measurement appears in two units in two places. This is the contract’s shape, not an accident, and it is the one thing worth reading before you bind a field to a label:

MeasurementAs a fractionAs a percentageIn currency
Growth on the starting balancegrowth.growth, summary.gain, evaluation.metrics.profit_percent—balance.table.total
Drawdown from the all-time peakgrowth.drawdownsummaryIndicators.drawdown—
Share of closed trades that won—tradeHistory.summary.winRate—
The rule limitsevaluation.rulesApplied.*——

summary.gain is a fraction, not money

summary.gain is growth on the starting balance as a fraction (-0.0546 means down 5.46%) — the same number as growth.growth and evaluation.metrics.profit_percent. The money form is balance.table.total, which equals tradeHistory.summary.totalProfit and profitTotal.profit + profitTotal.loss.

summary.activity is a fraction too: the share of the account’s life that has had trading on it, capped at 1. The deal count is tradeHistory.totalDeals.

Response

200 OK (abridged)
{
  "account": 10000042,
  "name": "$1K One Step",
  "broker": "Northwind Funding",
  "currency": "USD",

  "balance": {
    "balance": 945.19,
    "equity": 945.19,
    "period": 3600,
    "chart": [
      { "x": 1771415040, "y": [1000, 1000] },
      { "x": 1788795349, "y": [945.19, 945.19] }
    ],
    "table": {
      "years": [{ "year": 2026, "months": { "1": 15.8, "2": -8.74 }, "yearly": 7.06 }],
      "total": 7.06
    }
  },

  "_id": "9f1c…",
  "type": "demo",
  "digits": 2,
  "credentialKey": "1K_ONE_STEP",
  "status": "ACTIVE",
  "isBreached": false,
  "breachReasons": [],
  "statusChangedAt": null,
  "updatedAt": "2026-09-29T08:41:02Z",
  "__v": 1,

  "summary": {
    "gain": -0.054576,
    "activity": 0.36,
    "deposit": [1000, 1],
    "withdrawal": [0, 0],
    "dividend": 0, "correction": 0, "credit": 0
  },

  "summaryIndicators": {
    "sharp_ratio": -0.8,
    "profit_factor": 0.72,
    "recovery_factor": -0.5,
    "drawdown": 9.36,
    "deposit_load": 0.0797,
    "trades_per_week": 3.2,
    "hold_time": 7047
  },

  "risksIndicators": {
    "profit": [21.94, -12.36],
    "max_consecutive_trades": [2, 16],
    "max_consecutive_profit": [37.61, -74.44]
  },

  "growth": {
    "growth": -0.054576,
    "drawdown": 0.093599,
    "period": 3600,
    "chart": [
      [{ "x": 1771415040, "y": [0.01] }],
      [{ "x": 1771415040, "y": [0.002] }]
    ],
    "table": { "years": [], "total": -0.054576 }
  },

  "drawdown": {
    "drawdown": 0.093599, "deposit_load": 0.0797, "period": 3600,
    "chart": [[…fraction], […currency], [0…], [0…]]
  },
  "dividend": { "dividend": 0, "correction": 0, "credit": 0, "period": 3600, "chart": [], "table": {} },

  "profitMoney": { "period": 3600, "profit": [], "loss": [], "table": {} },
  "profitDeals": { "period": 3600, "profit": [], "loss": [], "table": {} },
  "profitType": {
    "robot":   { "x": 0, "y": [0, 0] },
    "manual":  { "x": 0, "y": [50, -104.56] },
    "signals": { "x": 0, "y": [0, 0] }
  },

  "longShortDaily": { "chart": [{ "x": 0, "y": [13, 8] }] },

  "risksMfeMaeMoney":   { "max_avg_profit": 0, "max_avg_mfe": 0, "min_avg_loss": 0, "min_avg_mae": 0, "period": 3600, "chart": [[]] },
  "risksMfeMaePercent": { "max_avg_profit_ratio": 0, "max_avg_mfe_ratio": 0, "min_avg_loss_ratio": 0, "min_avg_mae_ratio": 0, "period": 3600, "chart": [[]] },

  "symbolIndicators": {
    "profit_factor": [["US500", 1.51]], "netto_profit": [["US500", 10.16]], "fees": [["US500", 0]]
  },
  "symbolTypes":  { "type": [["Index", 89], ["Currency", 4]] },
  "symbolsTotal": { "total": [["US500", 10.16, 9]] },
  "tradeTypeTotal": { "robots": 0, "manual": 93, "signals": 0 },

  "longShort": {
    "period": 3600,
    "long":  [{ "x": 1771113600, "y": [2] }],
    "short": [{ "x": 1771113600, "y": [1] }],
    "all":   [{ "x": 1771113600, "y": [3] }]
  },

  "longShortTotal": { "long": 63, "short": 30 },

  "longShortIndicators": {
    "netto_pl":               [-25.15, -29.41],
    "average_pl":             [-0.399206, -0.980333],
    "average_pl_percent":     [-0.000399, -0.00098],
    "commissions":            [0, 0],
    "average_profit":         [2.32127, 2.529333],
    "average_profit_percent": [0.002321, 0.002529],
    "trades":                 [63, 30],
    "win_trades":             [14, 12]
  },

  "profitDaily": {
    "chart": [
      { "x": 0, "y": [38.06, -92.02] },
      { "x": 1, "y": [16.94, -61.25] },
      { "x": 2, "y": [61.21, -10.84] },
      { "x": 3, "y": [51.9, -49.63] },
      { "x": 4, "y": [54.01, -62.94] },
      { "x": 5, "y": [0, 0] },
      { "x": 6, "y": [0, 0] }
    ]
  },

  "symbolDeals": {
    "period": 604800,
    "chart": [
      ["US30",  [{ "x": 1771113600, "y": [2] }, { "x": 1771718400, "y": [7] }]],
      ["US500", [{ "x": 1771113600, "y": [3] }, { "x": 1771718400, "y": [0] }]]
    ]
  },

  "symbolMoney": {
    "period": 604800,
    "chart": [
      ["US30",  [{ "x": 1771113600, "y": [11.52] }, { "x": 1771718400, "y": [6.92] }]],
      ["US500", [{ "x": 1771113600, "y": [14.7] }, { "x": 1771718400, "y": [18.98] }]]
    ]
  },

  "tradeHistory": {
    "fromDate": "2026-02-18T11:45:20Z",
    "toDate": "2026-09-29T08:41:02Z",
    "fetchedAt": "2026-09-29T08:41:02Z",
    "dayOffsetHours": 0,
    "totalDeals": 93,
    "deals": [{
      "ticket": 1000123, "order": 1000123, "position_id": 1000123,
      "time": 1771113600, "time_msc": 1771113600000, "time_iso": "2026-02-15T00:00:00Z",
      "type": 0, "type_name": "BUY",
      "entry": 1, "entry_name": "OUT",
      "magic": 0, "reason": 0,
      "volume": 0.16, "price": 52049,
      "commission": 0, "swap": 0, "fee": 0,
      "profit": -10.5, "net_profit": -10.5,
      "is_closing": true, "symbol": "US30",
      "comment": "", "external_id": ""
    }],
    "trades": [{
      "positionId": 1000123, "symbol": "US30", "side": "BUY", "volume": 0.16,
      "openTime": 1771113600, "openTimeIso": "2026-02-15T00:00:00Z", "openPrice": 52049,
      "closeTime": 1771117200, "closeTimeIso": "2026-02-15T01:00:00Z", "closePrice": 51983,
      "durationSeconds": 3600,
      "profit": -10.5, "commission": 0, "swap": 0, "fee": 0, "netProfit": -10.5,
      "entries": [{
        "time": 1771113600, "timeIso": "2026-02-15T00:00:00Z",
        "type_name": "BUY", "entry": 0, "entry_name": "IN",
        "price": 52049, "volume": 0.16, "cumulativeVolume": 0.16
      }],
      "entryCount": 1, "firstLegVolume": 0.16, "maxLegVolume": 0.16,
      "volumeMultiple": 1, "isAveraging": false, "isMartingale": false
    }],
    "dailyNet": {
      "2026-02-15": { "netProfit": -10.5, "grossProfit": -10.5, "closedDeals": 1 }
    },
    "summary": {
      "totalProfit": -54.56,
      "netProfit": -54.56,
      "totalCommission": 0, "totalSwap": 0, "totalFee": 0,
      "winningTrades": 26,
      "losingTrades": 67,
      "totalClosedTrades": 93,
      "winRate": 27.96,
      "symbolsTraded": ["US30", "US500"],
      "tradingDays": 31,
      "averagingPositions": 0, "martingalePositions": 0,
      "averagingDetected": false, "martingaleDetected": false
    }
  },

  "evaluation": {
    "program": "1_STEP",
    "evaluatedAt": "2026-09-29T08:41:02Z",
    "credentialKey": "1K_ONE_STEP",
    "rulesApplied": {
      "profit_target": 0.1,
      "max_loss_limit": 0.06,
      "daily_loss_limit": 0.03,
      "leverage": "1:50",
      "min_trading_days": 3,
      "min_profitable_days": null,
      "max_inactivity_days": 14
    },
    "status": "ACTIVE",
    "isBreached": false,
    "breaches": [],
    "breachReasons": [],
    "metrics": {
      "initial_balance": 1000,
      "current_balance": 945.19,
      "current_equity": 945.19,
      "worst_balance_or_equity": 945.19,
      "profit_percent": -0.0548,
      "profit_target_hit": false,
      "profitable_days": 11,
      "consecutive_inactive_days": 4,
      "daily_dd_total_days_checked": 31,
      "daily_dd_peak_equity": 1000,
      "daily_dd_threshold": 970,
      "daily_dd_current_drawdown_pct": 0.05481,
      "daily_dd_breached": true,
      "daily_dd_breach_date": null,
      "max_open_lots_limits": {},
      "freedom_lot_peaks": {},
      "freedom_lot_would_breach": []
    }
  },

  "profitTotal": {
    "profit": 50,
    "profit_gross": 50,
    "profit_dividend": 0,
    "profit_swap": 0,
    "loss": -104.56,
    "loss_gross": -104.56,
    "loss_commission": 0
  }
}
accountinteger
The 8-digit account number — the same one the trader types into the terminal.
namestring
The account type's name — the challenge this account is running.
brokerstring
Your organization’s name. There is no broker: fills are simulated against live prices and never routed to a venue. The field keeps the contract’s name and carries the firm whose executor the account trades on.
currencystring
Always "USD". Every account on the platform is denominated in USD today.

balance

balancenumber
Closed-trade equity: the starting balance plus every realized P&L.
equitynumber
Balance plus the floating P&L of everything still open. This is the number rules are judged on.
chartpoint[]
x a Unix second, y the pair [balance, equity] — balance first. Bucket width is chosen from the span you asked for. Empty when the equity curve is not available on your deployment; see equity curve.
tableobject
Realized P&L by calendar month and year. Months are keyed by month number as a string ("1" … "12") and a month with no trading is absent rather than zero, so iterate the keys you get rather than 1–12. Computed from the ledger, never from the chart.

summaryIndicators

sharp_rationumber
Annualized Sharpe ratio of daily realized returns against the starting balance, on 252 trading days. 0 when there is not enough history to measure a deviation — two days of trading has no meaningful one, and a number derived from it would be worse than none. (Spelled without the ‘e’ because the contract spells it that way.)
profit_factornumber
Gross profit over gross loss. 0 for an account with no losing trade — it has no ratio, and Infinity is not JSON a client can parse.
recovery_factornumber
Net profit over the worst drawdown, in currency.
drawdownnumber
How far below its all-time peak equity the account is now, as a percentage. The same measurement max-loss rules are enforced against.
trades_per_weeknumber
The lifetime average, not a recent rate.

risksIndicators

The streak view, read over closed deals in the order they settled. Every field is a two-element [best, worst] pair: index 0 describes winning, index 1 losing, and the losing figures are negative.

profit[number, number]
The largest single winning deal, and the largest single losing deal.
max_consecutive_trades[integer, integer]
The length of the longest unbroken run of winners, and of losers.
max_consecutive_profit[number, number]
What those two runs made and lost. The money always belongs to a run of the length above — where two runs tie on length, the more extreme one is reported.

profitDaily

Realized P&L by day of week: seven points, x = 0 for Monday through 6 for Sunday, y = [profit, loss] for that weekday across the whole ledger. Loss is negative, both are 0 for a day never traded, and every day is present so you can index the array directly. A deal counts on the day it settled, not the day it opened.

longShort

Three parallel series counting positions opened per bucket — the question a long/short chart answers is when exposure was taken on, not when it was closed. Every bucket in the range appears in all three series at the same x, so you can index them against each other without aligning timestamps, and all is always long + short for its bucket. longShortDaily is the same split by weekday, Monday first, as [long, short].

longShortTotal and longShortIndicators

The same split as scalars. longShortTotal is the deal count per direction — the totals of the series above, carried so you do not have to sum a chart to label a donut. longShortIndicators is how each direction performed, and every field in it is a two-element array indexed [long, short].

Counts include open positions, money does not: exposure was taken long the moment the position opened, but it has realized nothing until it closes. That is the same split tradeHistory.summary makes between totalDeals and totalClosedTrades.

netto_pl[number, number]
Net realized P&L per direction. The two sum to summary.gain.
average_pl[number, number]
netto_pl over the direction’s total deal count, open positions included — not over its closed count. The contract’s own definition, and the reason it is not netto_pl / win_trades.
average_pl_percent[number, number]
average_pl as a FRACTION of the starting balance.
commissions[number, number]
Always [0, 0] — no commission is modelled, for the same reason profitTotal’s gross and net pairs are equal. An explicit zero, not an omission.
average_profit[number, number]
The average WINNING deal per direction — gross profit over win_trades, so losers do not drag it down. 0 for a direction that has never won.
average_profit_percent[number, number]
average_profit as a FRACTION of the starting balance.
trades[integer, integer]
Every deal per direction, open ones included. The same two numbers as longShortTotal.
win_trades[integer, integer]
Closed deals that settled at or above zero, per direction. Note that trades counts open positions too, so it is not the denominator for a per-side win rate.

symbolDeals and symbolMoney

One series per instrument over the same buckets as balance.chart. Both objects carry period (the bucket width in seconds) and chart, a list of positional [symbol, points] pairs — a two-element array, not an object — sorted alphabetically by instrument. Every symbol gets every bucket in the range, leading zeros included, so the series are index-aligned with each other and with longShort.

symbolDealsseries
Positions opened per bucket, so a symbol’s series sums to its deal count.
symbolMoneyseries
Running realized P&L per bucket, banked when each position closed — so a symbol’s last point is its contribution to summary.gain, and the last points of every symbol add up to it.

tradeHistory

totalDealsinteger
Every trade on the account, open and closed. Always the true count, even when the list below is capped.
dealsdeal[]
Newest first, capped at 5,000. Truncation drops the oldest.
deals[].ticketinteger
The deal's display identifier, unique across the platform.
deals[].timeinteger
When the position was OPENED, as a Unix second.
deals[].type_namestring
"BUY" or "SELL".
deals[].volumenumber
Position size in lots.
deals[].pricenumber
The entry price. A closed deal's exit price is not in this shape — read it from the trades endpoint if you need it.
deals[].profitnumber
Realized P&L, and 0 while the position is still open. An open position’s floating P&L is a price-dependent number that would make two calls a second apart disagree; totalClosedTrades tells you how many of the deals are settled.
deals[].symbolstring
The instrument, in the platform's canonical naming.
summary.winRatenumber
Percentage of CLOSED trades that won. Open positions do not dilute it.
summary.netProfitnumber
Identical to totalProfit: the simulator charges no commission and no swap, so there is nothing to subtract. Both are reported so a client reading either gets a correct number.
summary.symbolsTradedstring[]
Every instrument the account has ever traded, sorted.

evaluation

The terms this account is judged against — read from the rule set version that was frozen onto it at creation, never from its rule set’s current version. Editing a rule set never changes the terms of accounts already running under it, and this object reflects that.

programstring
Always "1_STEP". An account points at exactly one rule set version for its whole life — there is no phase 1 → phase 2 progression and no funded stage on this platform, so every account genuinely is a single step. Reported as a constant so you can switch on it.
rulesApplied.profit_targetnumber | null
Target as a fraction of the starting balance (0.1 = +10%). null when the rule set has no profit target, which means the account can never pass — not 0, which would say it already has.
rulesApplied.max_loss_limitnumber | null
Maximum drawdown as a fraction. null when the rule set does not include one.
rulesApplied.daily_loss_limitnumber | null
Daily drawdown as a fraction. null when the rule set does not include one.
rulesApplied.leveragestring
The FX ratio, as "1:50". Leverage is set per asset class on this platform, and FX is reported as the single representative value an account-level field can carry. See rule sets for the per-class map.
statusstring
ACTIVE, BREACHED, PASSED or CLOSED, uppercased.
isBreachedboolean
True exactly when status is BREACHED.
breachesobject[]
One entry per breached rule: { rule, severity, observed, threshold, message }, plus peak_equity and breach_date on a drawdown breach. observed and threshold are null for a rule with no number to report. The rule that ended the account comes first; any other limit the account is also past follows it. Empty for a breach an administrator recorded by hand. See the note below.
breachReasonsstring[]
The rule codes that ended the account — DAILY_DRAWDOWN, MAX_LOSS_LIMIT, INACTIVITY, or a typed rule's key uppercased (e.g. MAX_LOT_PER_ORDER). A breach an administrator recorded by hand carries its own text instead.
metrics.profitable_daysinteger
Distinct UTC days whose realized P&L summed positive. Not the same as a rule set’s min_trading_days, which counts days traded at all.
metrics.profit_percentnumber
Growth as a fraction, measured on EQUITY so an open position counts toward it.

breaches is not a history

The first entry is the rule that ended the account, recorded in the same transaction as the status change. Any further entries are other breach rules of the account's frozen rule set that its equity is also past right now. It is not a log you can page through, and a second breach cannot happen to an account that is already breached.

Rules that flag rather than breach are a different thing entirely: they accumulate, trading continues, and they are not in this array. They are reported separately — see rule sets.

profitTotal

Gross profit and gross loss over closed trades. loss and loss_gross are negative. The net and gross pairs are identical because no trading costs are modelled — adding commission or swap would change the simulator’s P&L and every drawdown that follows from it, so it is a product decision rather than a field we can fill in quietly.

Blocks that are structurally zero

The report serves the whole of its contract, including the parts a broker-backed account would fill and a simulator cannot. Those are explicit zeros and empty collections, never missing keys, so a client binding to them renders an empty panel instead of undefined:

  • dividend, summary.withdrawal, summary.dividend/correction/credit — a challenge account is funded once and never paid into or out of again.
  • profitTotal.profit_swap, profitTotal.loss_commission, longShortIndicators.commissions, symbolIndicators.fees and the cost totals in tradeHistory.summary — no commission or swap is modelled.
  • profitType.robot / signals and tradeTypeTotal — every fill comes through one order path, so everything is manual.
  • risksMfeMaeMoney and risksMfeMaePercent — measuring how far a position ran in favour or against needs every tick it lived through recorded against it, and only the open and close prices are stored. Reporting anything else would be a guess dressed as a measurement.
  • evaluation.metrics.freedom_lot_peaks and freedom_lot_would_breach — peak concurrent lots per asset class needs an exposure history nothing records. max_open_lots_limits carries at most the key ALL, because the lot ceiling here is account-wide rather than per class.
  • tradeHistory.summary.averagingDetected / martingaleDetected and their counts — a position cannot be added to on this platform, so there is no scaling-in pattern to find.

What this object does not carry

  • A deposit history. A challenge account’s only deposit is the starting balance it was provisioned with, so summary.deposit is the contract’s [amount, count] pair with a count of 1 for the account’s whole life — the same number as metrics.initial_balance.
  • Commission, swap, dividends and corrections. Not modelled — see profitTotal above.
  • An order source. There is no robot / signal / manual distinction; every fill comes through the same path.
  • The trader’s identity. A report is about an account. The trader record holding it is on traders, and an API key never reaches a trader login.

One thing to know about history

The balance line in balance.chart is exact for the account’s whole life — it is reconstructed from the ledger. The equity line needs the floating value of open positions at each moment, which is only recorded from the day the equity curve shipped on your deployment. For any earlier period the two lines are equal and intraday dips from open losing positions are not visible.