History & Bars
The History endpoint lets you retrieve historical OHLCV (Open, High, Low, Close, Volume) bar data for any available instrument. Use this to pre-load data for indicator calculations, analyze historical price patterns, or build lookback buffers before entering the replay loop.
POST History/retrieveBars
Retrieve historical bars for a contract. You can request data by specifying the number of bars to look back, or by defining a time window with start/end timestamps.
URL: POST /api/topstep-sim/History/retrieveBars
Authentication: Bearer token required.
Request body
{ "contractId": "CON.F.US.ENQ.H25", "unit": 2, "unitNumber": 5, "barsBack": 200, "startTime": null, "endTime": null}| Field | Type | Required | Description |
|---|---|---|---|
contractId | string | Yes | The contract ID to retrieve data for |
unit | number | Yes | Bar aggregation unit. See AggregateBarUnit below. |
unitNumber | number | Yes | Number of units per bar (e.g., 5 with unit=2 gives 5-minute bars) |
barsBack | number or null | No | Number of bars to retrieve, counting back from the current time or endTime. Cannot be used together with startTime. |
startTime | string or null | No | ISO 8601 start timestamp. Retrieve bars from this time forward. Cannot be used together with barsBack. |
endTime | string or null | No | ISO 8601 end timestamp. Defaults to the current session time if not specified. |
AggregateBarUnit
| Value | Unit |
|---|---|
1 | Second |
2 | Minute |
3 | Hour |
4 | Day |
Common timeframe configurations
| Timeframe | unit | unitNumber |
|---|---|---|
| 1-second | 1 | 1 |
| 1-minute | 2 | 1 |
| 5-minute | 2 | 5 |
| 15-minute | 2 | 15 |
| 30-minute | 2 | 30 |
| 1-hour | 3 | 1 |
| 4-hour | 3 | 4 |
| Daily | 4 | 1 |
Response
{ "success": true, "errorCode": 0, "errorMessage": null, "bars": [ { "t": "2025-01-15T14:00:00Z", "o": 21480.50, "h": 21495.25, "l": 21478.00, "c": 21492.75, "v": 3420 }, { "t": "2025-01-15T14:05:00Z", "o": 21492.75, "h": 21505.50, "l": 21490.00, "c": 21503.25, "v": 2815 } ]}| Field | Type | Description |
|---|---|---|
bars | array | List of bar objects in chronological order (oldest first) |
bars[].t | string | ISO 8601 timestamp for the bar’s open time |
bars[].o | number | Open price |
bars[].h | number | High price |
bars[].l | number | Low price |
bars[].c | number | Close price |
bars[].v | number | Volume (number of contracts traded) |
Example: Look back N bars
# Get the last 200 5-minute barsresult = api("History/retrieveBars", { "contractId": CONTRACT_ID, "unit": 2, # Minute "unitNumber": 5, # 5-minute bars "barsBack": 200})
if result["success"]: bars = result.get("bars", []) print(f"Retrieved {len(bars)} bars")
# Calculate a simple moving average from historical data closes = [b["c"] for b in bars] sma_20 = sum(closes[-20:]) / 20 print(f"SMA(20) = {sma_20:.2f}")curl -X POST https://api.test-max.com/api/topstep-sim/History/retrieveBars \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "contractId": "CON.F.US.ENQ.H25", "unit": 2, "unitNumber": 5, "barsBack": 200 }'Example: Time window
# Get all 1-minute bars between 14:00 and 15:00 UTCresult = api("History/retrieveBars", { "contractId": CONTRACT_ID, "unit": 2, # Minute "unitNumber": 1, # 1-minute bars "startTime": "2025-01-15T14:00:00Z", "endTime": "2025-01-15T15:00:00Z"})
bars = result.get("bars", [])print(f"Retrieved {len(bars)} bars in the 14:00-15:00 window")Building a lookback buffer
Many strategies require historical data to calculate indicators (e.g., moving averages, RSI, Bollinger Bands) before entering the replay loop. Use History/retrieveBars to pre-load this data:
# Pre-load 50 bars for SMA calculationhistory = api("History/retrieveBars", { "contractId": CONTRACT_ID, "unit": 2, "unitNumber": 5, "barsBack": 50})
closes = [b["c"] for b in history.get("bars", [])]
# Now enter the replay loop with a warm indicatorfor i in range(TOTAL_BARS): bar = get_next_bar() if bar is None: break
closes.append(bar["c"])
# Need at least 20 bars for SMA(20) if len(closes) >= 20: sma = sum(closes[-20:]) / 20 if bar["c"] > sma: # Price above SMA — bullish signal passMulti-timeframe analysis
You can retrieve bars at different timeframes for the same instrument. This is useful for strategies that use a higher timeframe for trend direction and a lower timeframe for entries.
# Get daily bars for trend contextdaily = api("History/retrieveBars", { "contractId": CONTRACT_ID, "unit": 4, # Day "unitNumber": 1, # Daily "barsBack": 20})
daily_bars = daily.get("bars", [])daily_closes = [b["c"] for b in daily_bars]daily_sma = sum(daily_closes[-10:]) / 10daily_trend = "bullish" if daily_closes[-1] > daily_sma else "bearish"
# Get hourly bars for recent structurehourly = api("History/retrieveBars", { "contractId": CONTRACT_ID, "unit": 3, # Hour "unitNumber": 1, # 1-hour bars "barsBack": 24})
hourly_bars = hourly.get("bars", [])recent_high = max(b["h"] for b in hourly_bars[-4:])recent_low = min(b["l"] for b in hourly_bars[-4:])
print(f"Daily trend: {daily_trend}")print(f"4-hour range: {recent_low} — {recent_high}")Usage notes
- Bars are returned in chronological order (oldest first).
- Use either
barsBackorstartTimeto define the data range — not both. - If
endTimeis omitted, data is returned up to the current point in the replay session. - The maximum number of bars per request depends on the instrument and timeframe. For high-frequency data (1-second bars), consider limiting
barsBackto avoid large responses. - Historical bar data uses the same format as bars returned by
Replay/step. See Bar Data Format for full field documentation.