Skip to main content

Calls, Call Episodes and Positioning

When an account or channel posts that it is long or short an asset, Elfa records it, at three levels:

EndpointOne row isAnswers
/v3/callsA call: one post that took or changed a positionWhat did accounts post?
/v3/calls/episodesA call episode: one position, from open to closeWhat does an account hold, and how did it end?
/v3/calls/positioningOne asset, nowHow many are long and short it?
calls     open SPY ─▶ reaffirm ─▶ trim ─▶ close     4 posts: episodeId
episode long SPY, closed 1 position: calls[].callId

Not returned: post text, a recommendation, or a win flag per position. An episode has its entry and exit prices; track scores the author across all of them.

Filtering by Account​

Both sources appear unless you filter by handle:

XTelegram
sourcetwittertelegram
handleThe X account, e.g. 3PeaksTradingnull
channelnullThe channel or group it was posted in, never the poster. Null when we cannot name it

handle takes X accounts only, with or without @, any case, up to 40 characters. Telegram channels cannot be filtered on yet: filter by entityIds and time, and keep the rows whose channel matches. An X account we hold with no calls returns an empty list.

Calls​

GET /v3/calls: calls in a time range, newest first, or up to 30 by id.

{
"calls": [
{
"id": "07465e06-12bd-4117-b68d-0226d3faed1e",
"episodeId": "9dfbbc44-4919-4da7-9999-426d83963d5d",
"handle": "3PeaksTrading",
"source": "twitter",
"channel": null,
"asset": {
"id": "42703feb-7611-4c9d-8062-b455bae2bcc5",
"symbol": "SPCX",
"name": "Space Exploration Technologies Corp. Class A Common Stock",
"entityType": "equity"
},
"callAction": "close",
"setup": null,
"thesis": null,
"sourceRecordId": "2107190165538320484",
"occurredAt": 1791228259
},
{
"id": "8a069b20-aef5-4fb9-984c-de7a6a6cd826",
"episodeId": "3809d877-e764-437c-a58f-a237a1b0ca35",
"handle": null,
"source": "telegram",
"channel": "J7’s - Trading Journal (笔记) 📝",
"asset": {
"id": "5a158802-db76-4bd5-b962-9e0c512222ef",
"symbol": "NEAR",
"name": "NEAR Protocol",
"entityType": "token"
},
"callAction": "open",
"setup": "technical",
"thesis": null,
"sourceRecordId": "telegram_group:59eff3d5c0ca5f8f2525b5220194d56e",
"occurredAt": 1791188119
}
],
"nextCursor": null,
"hasMore": false,
"servedFrom": null
}

GET /v3/calls?callIds=8a069b20-aef5-4fb9-984c-de7a6a6cd826,07465e06-12bd-4117-b68d-0226d3faed1e, read from production on 6 October 2026: an account closing a long, and a channel opening one.

FieldMeaning
idThe call id. Pass it back in callIds
episodeIdIts call episode
handle, source, channelThe X account, or the channel or group it was posted in. source is null when the post cannot be traced
assetid (a family id), symbol, name, entityType. Null when we cannot name it
callActionopen, reaffirm, add, trim, reverse, close or stopOut. See Call
setupHow the post reads the trade: technical, momentum, fade (against the move) or accumulation. Null if unsaid
thesisWhat will drive the move: macro, narrative or event. Null if unsaid
sourceRecordIdThe post. On X its id: https://x.com/i/web/status/<id>. On Telegram, a reference to a group of messages
occurredAtWhen the post was made

One post can be two calls. A reverse closes one episode and opens the opposite one, so it appears twice with the same sourceRecordId. A second open in a direction already held is recorded as reaffirm.

Parameters​

ParameterValuesDefaultNotes
fromUnix secondsrequired unless callIdsAgainst occurredAt
toUnix secondsnow
handleX handleSee Filtering by Account
entityIdsup to 30 token or equity ids, a listCalls on any of them
callIdsup to 30 call ids, a listOther filters still apply
orderdesc, ascdesc
limit1 to 3010
cursor

/v3/calls has no market filter. For one market, filter episodes by assetClass and fetch their calls.

Errors​

The common errors apply. Calls, episodes and positioning take tokens and equities only: a person, project or organisation id is a 400, … is not an asset family.

Call Episodes​

GET /v3/calls/episodes: call episodes open at any point in a time range, newest opened first, or up to 30 by id.

{
"episodes": [
{
"id": "9dfbbc44-4919-4da7-9999-426d83963d5d",
"handle": "3PeaksTrading",
"source": "twitter",
"channel": null,
"asset": {
"id": "42703feb-7611-4c9d-8062-b455bae2bcc5",
"symbol": "SPCX",
"name": "Space Exploration Technologies Corp. Class A Common Stock",
"entityType": "equity"
},
"direction": "long",
"horizon": "swing",
"status": "closed",
"openedAt": 1791210989,
"closedAt": 1791228259,
"observedAt": 1791211102,
"entryPrice": 164.29,
"exitPrice": 168.04,
"closeReason": "close",
"setup": "technical",
"thesis": "event",
"statedTarget": 180,
"statedStop": null,
"track": {
"alphaScore": -0.027325837327777693,
"hitRate": 0.42424242424242425,
"avgReturn": 0.006040354648865286,
"scoredEpisodes": 66,
"totalEpisodes": 104
},
"calls": [
{ "callId": "16e05ecf-1cee-42b1-92fd-735c014e3adb", "callAction": "open", "occurredAt": 1791210989 },
{ "callId": "07465e06-12bd-4117-b68d-0226d3faed1e", "callAction": "close", "occurredAt": 1791228259 }
]
},
{
"id": "3809d877-e764-437c-a58f-a237a1b0ca35",
"handle": null,
"source": "telegram",
"channel": "J7’s - Trading Journal (笔记) 📝",
"asset": {
"id": "5a158802-db76-4bd5-b962-9e0c512222ef",
"symbol": "NEAR",
"name": "NEAR Protocol",
"entityType": "token"
},
"direction": "long",
"horizon": "unspecified",
"status": "open",
"openedAt": 1791188119,
"closedAt": null,
"observedAt": 1791188894,
"entryPrice": 5.16425,
"exitPrice": null,
"closeReason": null,
"setup": "technical",
"thesis": null,
"statedTarget": 6,
"statedStop": null,
"track": {
"alphaScore": -0.14406656638938875,
"hitRate": 0.5333333333333333,
"avgReturn": 0.026908979741187455,
"scoredEpisodes": 30,
"totalEpisodes": 53
},
"calls": [
{ "callId": "8a069b20-aef5-4fb9-984c-de7a6a6cd826", "callAction": "open", "occurredAt": 1791188119 }
]
}
],
"nextCursor": null,
"hasMore": false,
"servedFrom": null
}

GET /v3/calls/episodes?episodeIds=9dfbbc44-4919-4da7-9999-426d83963d5d,3809d877-e764-437c-a58f-a237a1b0ca35, read from production on 6 October 2026: the episodes of the two calls above. The SPCX long closed about five hours after opening, at 168.04 against a 164.29 entry. The NEAR long is still open.

FieldMeaning
idThe episode id. Pass it back in episodeIds
handle, source, channelThe X account, or the channel or group, that holds it. source is where the opening post was made
assetAs on calls. Null when we cannot name it
directionlong or short
horizonscalp, swing, position or unspecified. A later post can change it. Sets the expiry
statusopen or closed
openedAt, closedAtThe opening post, and the close. closedAt is null while open
observedAtWhen we recorded it. See Point in Time
entryPrice, exitPriceUSD at open and at close. Null when we could not price it
closeReasonclose, reverse or stopOut by the account. expiry when nobody closed it
setup, thesisThe opening call's. Null when it gave none
statedTarget, statedStopThe prices the author named when opening. Null when none
trackThe author's record. See Track
callsIts calls, oldest first: callId, callAction, occurredAt

A position opened before your history keeps its prices and status, but lists only its calls inside the history, and its opening setup, thesis, statedTarget and statedStop are null.

Track​

The author's record over every position they have opened, in every market, not cut to your history. The same object is on top accounts. Scored daily from closed positions.

FieldMeaning
alphaScore-1 to 1. How well scored positions did, against the market (BTC for crypto, SPY for equities) and outright. Pulled toward 0 while there are few
hitRate0 to 1. Share of scored positions that made money
avgReturnMean realized return, direction-adjusted: 0.05 is 5%
scoredEpisodes, totalEpisodesClosed positions with a score, and every position opened

The three scores are null until the author has a scored position.

Expiry​

A position nobody closes expires after its last open, add, trim or reaffirm, with closeReason: "expiry" and closedAt set to the deadline. It can read open for up to a day past the deadline, until the expiry is recorded. Its exitPrice is read then, and is often null.

horizonscalpswingpositionunspecified
Expires after48 hours14 days90 days30 days

Point in Time​

An episode can be recorded hours after its post. To backtest what was known at a moment T:

  • keep episodes with observedAt <= T;
  • treat one with closedAt > T as still open at T;
  • use only calls with occurredAt <= T.

Parameters​

ParameterValuesDefaultNotes
fromUnix secondsrequired unless episodeIdsPositions open at any point since: still open, or closed at or after from
toUnix secondsnowOpened at or before to
handleX handleSee Filtering by Account
entityIdsup to 30 token or equity ids, a listEpisodes on any of them
statusopen, closedboth
directionlong, shortboth
assetClasscrypto, equitybothThe market of the episode's asset
episodeIdsup to 30 episode ids, a listOther filters still apply
orderdesc, ascdescBy openedAt
limit1 to 3010
cursor

status=open&from=<now> reads what every matching account holds right now.

Positioning​

GET /v3/calls/positioning: open long and open short episodes on one asset, right now, every source together. Counts, not shares, so two assets compare by size.

{
"id": "b23e0b47-deec-4161-b49c-7e2652f07fe6",
"symbol": "BTC",
"name": "Bitcoin",
"openLong": 3252,
"openShort": 402,
"asOf": 1790931501
}

GET /v3/calls/positioning?entityId=b23e0b47-deec-4161-b49c-7e2652f07fe6

FieldMeaning
id, symbol, nameThe asset's family
openLong, openShortOpen episodes each way, scalp included. One account can count on both sides
asOfWhen an open episode on it last changed. When none is open, when it was read

An episode past its expiry can count here for up to a day; the call books drop it at the deadline.

ParameterValuesNotes
entityIdone token or equity id, requiredSingular: entityIds is a 400