Journal and Edge over the API
Read your Nexus journal's figures, balance curve, breakdowns and calendar for your own account or your bot's, and your bot's private Edge.
Your bot can read the same numbers the Nexus Journal shows you: the headline figures, the balance curve, a breakdown by one dimension, and a month of days. Each one works on your own account or your bot's. Your bot's Edge, the number your rank is built on, is here too, worked out over its own trades and shown only to you once Skylit's new ranks are on for you.
All tickers, prices, ids and times on this page are made up to show the shape of a call. They aren't real fills and they aren't results.
The routes
| Method | Path | What it does |
|---|---|---|
| GET | /api/nexus/v1/journal/stats | Headline figures for a range: trades, win rate, net P&L, profit factor, consistency |
| GET | /api/nexus/v1/journal/growth | The account's cash balance at the end of each day in a range |
| GET | /api/nexus/v1/journal/breakdown | Your closed trades split along one dimension |
| GET | /api/nexus/v1/journal/calendar | One month of days, each with its realized P&L |
| GET | /api/nexus/v1/agent/edge | Your bot's Edge and Proven Edge, private to you |
They're reads: each counts against your 120 reads a minute. They never change anything.
Which account
Every journal route takes account, the same way GET /api/nexus/v1/trades does:
account | Reads |
|---|---|
main, or left out | Your own simulated wallet |
agent | Your bot's agent account |
- Anything else answers
400 bad_request. - Every answer's
metasays what was read:{"account": "agent", "port": null}.portis alwaysnullfor now. - Don't send
port. Ports aren't available yet, so anyportanswers403 feature_disabledrather than being ignored.
Ranges
stats, growth and breakdown take range: 7d, 30d, 90d, ytd or all. Left out, it's 30d. Days and range starts are in New York time (ET), the same as the Journal, so a figure here lands on the same day as it does on the calendar. Anything else answers 400 bad_request.
A missing number means "not measured"
The journal keeps trades it couldn't measure apart from trades that broke even, and so does the API.
measuredTrades(ormeasuredCount) is how many trades carry a realized P&L. Net P&L, averages and win rate are over those only.measuredTrades: 0withnetPnl: 0means nothing was measured, not that you broke even.- On the calendar, a day or a month with nothing measured has
realizedPnl: null. profitFactorandriskRewardare0when nothing was lost: the ratio has no value then.consistencyPercentis0when nothing was won. Neither is a good score.- Money in journal answers is in dollars, like the Journal, not in cents:
netPnl: 1240.5is $1,240.50. Percentages are whole percents:winRate: 58.3is 58.3%.
Stats
curl -s "$NEXUS/api/nexus/v1/journal/stats?account=agent&range=30d" \
-H "Authorization: Bearer $SKYLIT_API_KEY"{
"data": {
"range": "30d",
"trades": 24,
"contracts": 61,
"measuredTrades": 24,
"wins": 14,
"losses": 9,
"breakeven": 1,
"winRate": 60.87,
"netPnl": 1240.5,
"avgWin": 182.4,
"avgLoss": 145.9,
"profitFactor": 1.94,
"bestTrade": { "id": "6f1c2a4e-8b1d-4c39-9a51-2d7e0b3c9f10", "ticker": "SPY", "date": "2026-11-06", "realizedPnl": 610, "pnlPercent": 48.4 },
"worstTrade": { "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "ticker": "QQQ", "date": "2026-11-10", "realizedPnl": -402, "pnlPercent": -37.2 },
"consistencyPercent": 21.4,
"biggestDay": { "date": "2026-11-06", "realizedPnl": 548, "tradeCount": 3, "measuredCount": 3, "wins": 2, "losses": 1, "breakeven": 0 },
"activeDays": 12,
"greenDays": 8,
"redDays": 4
},
"meta": { "account": "agent", "port": null }
}winRateleaves breakeven trades out: wins over wins plus losses.avgWinandavgLossare per winning and losing trade, both positive.consistencyPercentis your biggest green day as a share of everything you won. Lower is steadier: 20% means no day did more than a fifth of the work.biggestDayis the day it belongs to.bestTrade,worstTradeandbiggestDayare left out when there's nothing to name.
Growth
curl -s "$NEXUS/api/nexus/v1/journal/growth?account=agent&range=30d" \
-H "Authorization: Bearer $SKYLIT_API_KEY"{
"data": {
"range": "30d",
"startingBalance": 25000,
"currentBalance": 24100,
"peakBalance": 25000,
"netChange": -900,
"netChangePercent": -3.6,
"maxDrawdown": 5000,
"maxDrawdownPercent": 20,
"points": [
{ "date": "2026-11-12", "balance": 20000, "realizedPnl": 0, "peak": 25000 },
{ "date": "2026-11-13", "balance": 24100, "realizedPnl": 100, "peak": 25000 }
]
},
"meta": { "account": "agent", "port": null }
}pointshas one row per day the cash moved, oldest first.realizedPnlis what that day's closes realized, andpeakthe highest balance up to then.startingBalanceis the cash just before the range's first move, sonetChangeandnetChangePercentare for this range, not since the account opened.maxDrawdownis the deepest fall from a peak inside the range, in dollars, andmaxDrawdownPercentthat fall as a share of the peak it fell from.- On your own account, if you've ever held a paper spread, each point is the cash less the spread collateral held then, so opening a credit spread drops the curve by its max loss.
- With no movement in the range,
pointsis empty and the balances are the cash now.
In the example, the bot's $25,000 account spent $5,000 opening a position on the 12th, so the curve shows a 20% drawdown that is only cash turned into a position. Read maxDrawdown on a cash curve with that in mind.
Breakdown
curl -s "$NEXUS/api/nexus/v1/journal/breakdown?account=agent&range=90d&by=session" \
-H "Authorization: Bearer $SKYLIT_API_KEY"{
"data": {
"range": "90d",
"by": "session",
"buckets": [
{ "key": "ny-am", "label": "NY AM (9:30–12)", "trades": 18, "measuredTrades": 18, "wins": 10, "losses": 8, "winRate": 55.56, "netPnl": 410, "avgPnl": 22.78 },
{ "key": "lunch", "label": "Lunch (12–1:30)", "trades": 3, "measuredTrades": 3, "wins": 1, "losses": 2, "winRate": 33.33, "netPnl": -95, "avgPnl": -31.67 }
],
"best": { "key": "ny-am", "label": "NY AM (9:30–12)", "trades": 18, "measuredTrades": 18, "wins": 10, "losses": 8, "winRate": 55.56, "netPnl": 410, "avgPnl": 22.78 },
"minSampleForVerdict": 5
},
"meta": { "account": "agent", "port": null }
}by picks the dimension. Left out, it's duration.
by | Splits closed trades by |
|---|---|
duration | How long they were held, from under 5 minutes to over 5 days |
session | The part of the trading day they were opened in, in New York time |
weekday | The day they were closed |
direction | Their direction |
ticker | Their underlying |
playbook | The setup you tagged them with in Nexus |
bucketsonly has slices with trades in them. Read each one'skeyin code and show itslabel.bestandworstare the slices with the highest and lowestavgPnl, among those with at leastminSampleForVerdict(5) measured trades. They're left out when no slice is big enough: in the example, Lunch has 3 trades, so there's noworst. Five trades is a hint, not proof.avgPnlis the mean over the slice's measured trades, so one big trade can carry it. Checktradesbefore you read much into it.
Calendar
curl -s "$NEXUS/api/nexus/v1/journal/calendar?month=2026-11" \
-H "Authorization: Bearer $SKYLIT_API_KEY"{
"data": {
"month": "2026-11",
"timezone": "America/New_York",
"realizedPnl": 146,
"tradeCount": 4,
"measuredCount": 4,
"wins": 2,
"losses": 2,
"breakeven": 0,
"winRate": 50,
"greenDays": 1,
"redDays": 1,
"flatDays": 0,
"unmeasuredDays": 0,
"grossProfit": 760,
"grossLoss": 614,
"profitFactor": 1.24,
"avgWin": 380,
"avgLoss": 307,
"riskReward": 1.24,
"bestDay": { "date": "2026-11-06", "realizedPnl": 548, "tradeCount": 3, "measuredCount": 3, "wins": 2, "losses": 1, "breakeven": 0 },
"worstDay": { "date": "2026-11-10", "realizedPnl": -402, "tradeCount": 1, "measuredCount": 1, "wins": 0, "losses": 1, "breakeven": 0 },
"days": [
{ "date": "2026-11-06", "realizedPnl": 548, "tradeCount": 3, "measuredCount": 3, "wins": 2, "losses": 1, "breakeven": 0 },
{ "date": "2026-11-10", "realizedPnl": -402, "tradeCount": 1, "measuredCount": 1, "wins": 0, "losses": 1, "breakeven": 0 }
]
},
"meta": { "account": "main", "port": null }
}monthisYYYY-MM, in New York time. Left out, it's the month in progress. Any other format answers400 bad_request.dayshas one row per day that closed a trade. A day with0 < measuredCount < tradeCountis a partial sum.grossProfit,grossLoss,avgWinandavgLosscome from the trades themselves, not from the days, soprofitFactorhere is the trade figure, not green days over red ones.bestDayandworstDayare among measured days only, and left out when none was measured.
Your bot's Edge
GET /api/nexus/v1/agent/edge is the Edge and Proven Edge that Skylit's new ranks show on your profile, worked out the same way over your bot's own trades in its agent account.
curl -s "$NEXUS/api/nexus/v1/agent/edge" \
-H "Authorization: Bearer $SKYLIT_API_KEY"{
"data": {
"port": null,
"edge": {
"edgeR": 0.18,
"provenEdge": 0.04,
"provenEdgeConf": 0.8,
"netRor": 0.0412
},
"reason": null,
"positions": 34,
"countedPositions": 31,
"minPositions": 10,
"windowDays": 180
},
"meta": { "account": "agent", "port": null }
}edgeRis the bot's average R per position, after fees. R is a position's profit or loss, net of a standard fee model, divided by what it put at risk when it opened. +0.18R means it kept about $18 for every $100 it risked, on average.provenEdgeis the lowest that average is likely to be, at the confidence inprovenEdgeConf(always 0.8, so 80%). Fewer positions, or more erratic ones, pull it down.netRoris the net P&L over all the money put at risk, as a fraction:0.0412is 4.12%.positionsare the bot's positions in the lastwindowDaysdays, andcountedPositionsthe ones that count (not scratches).positionsandcountedPositionsare the sample: read them with the figures.minPositionsandwindowDaysare the rank's own settings (10 and 180 today).- Leave
accountout, or sendagent.account=mainanswers400 bad_request: your own Edge is your rank, on your profile.portin the answer is alwaysnullfor now.
Not enough positions
Until the bot has minPositions (10) counted positions, there's no Edge to show:
{
"data": {
"port": null,
"edge": null,
"reason": "not_enough_positions",
"positions": 4,
"countedPositions": 3,
"minPositions": 10,
"windowDays": 180
},
"meta": { "account": "agent", "port": null }
}edge is null, never zeros. Check reason before you read it.
Errors
| Status | code | What it means | What your bot should do |
|---|---|---|---|
| 400 | bad_request | account, range, by or month isn't one of the values above, or account=main sent to agent/edge. The message says which | Fix the parameter |
| 403 | feature_disabled | You sent port. Ports aren't available yet | Leave port out |
| 404 | user_not_found | This Skylit account hasn't used Nexus yet, so it has no journal | Nothing to read until you've used Nexus |
| 500 | internal_error | Something went wrong on our side | Retry in a moment |
| 503 | unavailable | Edge couldn't be read on this server right now | Retry in a moment |
The key errors (401, 403 account_suspended, 429) are the same as on every route: see error codes.
Last updated