API reference

Current setups

GET/tickers/{symbol}/patternsKey required

Current setups on a ticker

Returns the setups the last nightly run sees on one ticker, any ticker the nightly covers: family and direction, the two lines as dated endpoints, the trigger rule and price, stop and target, and the family and ticker track records. An empty setups list means nothing is forming; available false means the nightly has no current book for the symbol. The ticker does not need to be tracked. Setups and their ids change nightly, so do not cache them across sessions.

Authentication

Needs a key: send Authorization: Bearer tp_live_… (see Authentication). Counted against the key's limits of 60 requests a minute and 10,000 a day.

Parameters

NameInTypeRequiredDescription
symbolpathstringyesExchange symbol, upper case (BRK.B, not BRK-B). Lower case is accepted and upper-cased.
X-TradingPal-ClientheaderstringnoOptional name of the agent or script making the call. It is recorded in the account's usage log so the user can see which client made which calls; the User-Agent is recorded when it is absent.

Request

curl "https://api.tradingpal.io/api/v1/tickers/NVDA/patterns" \
  -H "Authorization: Bearer $TRADINGPAL_API_KEY"

Response

JSON. The fields this route adds are below; every response also carries the envelope fields (api_version, as_of_session, data_version, source, disclaimer).

FieldTypeDescription
symbolstringThe symbol asked for, upper-cased.
availablebooleanTrue when the nightly has a current candidate book for the symbol. False when the symbol is excluded from pattern analysis or no current book exists; setups is then empty.
reasonstring · nullableWhy available is false, when the reason is known: not_covered means the symbol is excluded from pattern analysis. Absent when available is true, and when the nightly simply has no current book for the symbol.
setupsarray of SetupThe current setups, one per eligible candidate. Empty when nothing is forming.
stock_factsobject · nullableThe ticker's Stock facts as the TradingPal screener's quick view shows them: price and moves, performance, momentum (EMAs, RSI, moving averages), volume and volatility, and the company. Ticker facts, so they come once per answer, not per setup. Null when the ticker has no current facts.
stock_facts.as_ofstring · nullableWhen the facts were read, for example "Facts as of the Oct 6 close."
stock_facts.sectionsarray of objectGroups in the quick view's order: Price, Performance, Momentum, Volume and volatility, and Company (Asset for crypto). A missing fact is left out and an empty group dropped.
stock_facts.sections[].titlestringThe group's heading.
stock_facts.sections[].rowsarray of objectThe group's facts, in order.
stock_facts.sections[].rows[].labelstringFor example "EMA8 vs EMA21" or "RSI (14)".
stock_facts.sections[].rows[].valuestringReady to show, units included, for example "+2.5%", "$43B" or "59".
stock_facts.sections[].rows[].tonestring (enum)up or down on signed price moves; absent on other facts. One of up, down.
stock_facts.sections[].rows[].changestringOnly on the Last row: the day's change, for example "+0.40%".
stock_facts.sections[].rows[].change_tonestring (enum)up or down for change. One of up, down.
demobooleanTrue on the demo routes. Absent on the keyed route.
nextstring · nullableOn the demo routes, a sentence saying where to get a key for other tickers. Absent on the keyed route.

Example response

Response
{
  "api_version": "v1",
  "as_of_session": "2026-09-25",
  "symbol": "NVDA",
  "available": true,
  "setups": [
    {
      "setup_id": "NVDA:D:falling_wedge:1",
      "lineage_id": "lineage-1",
      "page_url": "https://www.tradingpal.io/screener/falling-wedge?interval=D&focus=NVDA&p=aB3",
      "symbol": "NVDA",
      "interval": "D",
      "family": "falling_wedge",
      "family_label": "Falling wedge",
      "pattern_type": "falling_wedge",
      "direction": "bullish",
      "status": "forming",
      "pattern_start": "2026-08-08",
      "pattern_end": "2026-09-07",
      "as_of_session": "2026-09-25",
      "last_close": 101.5,
      "price_scale": "log",
      "lines": {
        "upper": {
          "start": {
            "date": "2026-08-08",
            "price": 110
          },
          "end": {
            "date": "2026-09-07",
            "price": 104
          },
          "touch_count": 3,
          "touches": [
            {
              "date": "2026-08-08",
              "price": 111.2
            }
          ]
        },
        "lower": {
          "start": {
            "date": "2026-08-08",
            "price": 90
          },
          "end": {
            "date": "2026-09-07",
            "price": 98
          },
          "touch_count": 2,
          "touches": []
        }
      },
      "trigger_rule": "A daily close above the upper line; the trigger price moves with the line.",
      "plans": [
        {
          "direction": "bullish",
          "trigger_price": 105.25,
          "stop_price": 96,
          "target_price": 120
        }
      ],
      "track_record": {
        "family": {
          "scope": "family",
          "family": "falling_wedge",
          "symbol": null,
          "win_rate_pct": 54,
          "sample_size": 1287,
          "wins": 695,
          "losses": 592,
          "avg_win_pct": 8.1,
          "avg_loss_pct": -4.2,
          "median_win_pct": 6.3,
          "avg_trade_pct": 2.4,
          "avg_r": 0.41,
          "expected_r": 0.41,
          "profit_factor": 1.61,
          "avg_hold_bars": 11.2,
          "backtest_range": [
            "2006-09-25",
            "2026-09-25"
          ],
          "measured": "Every detector-confirmed breakout … open trades are excluded.",
          "summary": "Falling wedge: 1,287 resolved trades from 2006-09-25 to 2026-09-25; 54% reached the target, average win +8.1%, average loss -4.2%, median win +6.3%."
        },
        "ticker": null
      }
    }
  ],
  "stock_facts": {
    "as_of": "Facts as of the Sep 25 close.",
    "sections": [
      {
        "title": "Price",
        "rows": [
          {
            "label": "Last",
            "value": "$101.50",
            "change": "+0.40%",
            "change_tone": "up"
          },
          {
            "label": "Below 52-week high",
            "value": "6.5%"
          }
        ]
      },
      {
        "title": "Performance",
        "rows": [
          {
            "label": "1W",
            "value": "+6.2%",
            "tone": "up"
          },
          {
            "label": "1M",
            "value": "-3.5%",
            "tone": "down"
          }
        ]
      },
      {
        "title": "Momentum",
        "rows": [
          {
            "label": "vs EMA8",
            "value": "+1.2%"
          },
          {
            "label": "EMA8 vs EMA21",
            "value": "+2.5%"
          },
          {
            "label": "RSI (14)",
            "value": "59"
          }
        ]
      },
      {
        "title": "Volume and volatility",
        "rows": [
          {
            "label": "Relative volume",
            "value": "72nd percentile · last 3 months"
          },
          {
            "label": "Avg volume (20d)",
            "value": "2.5M · $381M/day"
          }
        ]
      },
      {
        "title": "Company",
        "rows": [
          {
            "label": "Market cap",
            "value": "$3.2T"
          },
          {
            "label": "Exchange · Country",
            "value": "Nasdaq · US"
          },
          {
            "label": "Type",
            "value": "Stock"
          }
        ]
      }
    ]
  }
}

Errors

Errors are JSON with the Error shape; the fix field says what to do.

StatusCodeMeaningFix
401missing_api_keyThe request had no Authorization: Bearer tp_live_… header and the route needs one.Send the header on every keyed call. Only the demo, families and universe routes answer without it.
401invalid_api_keyThe key is not one we know, or it has been revoked.Create a new key on the API Keys page and replace it wherever the old one was stored.
403forbiddenThe account behind the key is not on Premium+. API and MCP access requires Premium+ subscription at $30/month; Premium alone does not unlock the API.Get Premium+ ($30/month, all of the benefits in Premium plus API and MCP access) from the Quickstart, where a first subscription starts with 14 days free, or switch an existing Premium subscription to it there, then retry with the same key.
429rate_limitedThe key passed 60 requests in a minute or 10,000 in a day, or a keyless caller passed 30 a minute from one IP.Wait details.retry_after_seconds, then retry. Cache the nightly answers; they do not change until the next session.