This document outlines the RESTful API endpoints provided by the stochastix-core bundle.
- Base Path:
/api - Authentication: All endpoints are currently public and do not require authentication, as the application is designed for local/offline use.
- Data Format: All request and response bodies are
application/json.
GET /api/strategies- Description: Fetches a list of all available trading strategies and their configurable input parameters. This is used to dynamically build the "New Backtest" form in the UI.
- Requires: None
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
[ { "alias": "sample_strategy", "name": "Minimal EMA Crossover", "description": "A simple strategy based on Exponential Moving Average crossovers.", "inputs": [ { "name": "emaShortPeriod", "description": "Period for the short EMA", "type": "integer", "defaultValue": 12, "min": 1, "max": null, "choices": null }, { "name": "emaLongPeriod", "description": "Period for the long EMA", "type": "integer", "defaultValue": 26, "min": 1, "max": null, "choices": null } ] } ] - Error Responses:
500 Internal Server Error: If an error occurs while scanning for strategies.
-
GET /api/data/exchanges- Description: Retrieves a sorted list of all exchange IDs supported by the backend (via the CCXT library).
- Requires: None
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
[ "ace", "alpaca", "ascendex", "bequant", "bigone", "binance", "binancecoinm", "binanceus", "binanceusdm", "bingx" ]
-
GET /api/data-availability- Description: Scans the server for available market data (
.stchxfiles) and returns a manifest detailing available symbols, their timeframes, and the start/end dates for each dataset. - Requires: None
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
[ { "symbol": "ETH/USDT", "exchange": "okx", "timeframes": [ { "timeframe": "5m", "startDate": "2025-01-01T00:00:00Z", "endDate": "2025-04-01T00:20:00Z", "recordCount": 25925 }, { "timeframe": "1h", "startDate": "2024-01-01T00:00:00Z", "endDate": "2025-05-01T00:00:00Z", "recordCount": 11641 } ] } ] - Error Responses:
500 Internal Server Error: If an error occurs during the filesystem scan.
- Description: Scans the server for available market data (
-
POST /api/data/download- Description: Queues a new market data download for asynchronous execution. Returns a unique
jobIdimmediately, which can be used to listen for real-time progress updates via Mercure. - Requires: None
- Request Body: (
Stochastix\Domain\Data\Dto\DownloadRequestDto)exchangeId(string, required): The exchange ID (e.g., "binance", "okx").symbol(string, required): The trading symbol (e.g., "BTC/USDT").timeframe(string, required): The timeframe to download (e.g., "1h", "1d").startDate(string, required,YYYY-MM-DD): The start date for the download.endDate(string, required,YYYY-MM-DD): The end date for the download.
- Example Request Body:
{ "exchangeId": "binance", "symbol": "BTC/USDT", "timeframe": "1d", "startDate": "2023-01-01", "endDate": "2024-01-01" } - Success Response:
202 Accepted - Example Success Response Body:
{ "status": "queued", "jobId": "download_666c1e5a7b8d9" } - Error Responses:
400 Bad Request: Invalid input (e.g., validation errors in the request body, end date before start date).500 Internal Server Error: If the download message could not be dispatched to the queue.
- Description: Queues a new market data download for asynchronous execution. Returns a unique
-
DELETE /api/data/download/{jobId}- Description: Requests the cancellation of a running download job. The cancellation may take a few moments to take effect, as it is checked between data chunk fetches.
- Requires: None
- URL Parameters:
jobId(string, required): The unique ID of the download job to cancel.
- Request Body: None
- Success Response:
202 Accepted - Example Success Response Body:
{ "status": "cancellation_requested", "jobId": "download_666c1e5a7b8d9" } - Error Responses: None.
-
GET /api/data/inspect/{exchangeId}/{symbol}/{timeframe}- Description: Inspects a specific market data file (
.stchx). Returns the file's header metadata, a sample of the first and last records, and a full data consistency validation report (checking for gaps, duplicates, and out-of-order records). - Requires: None
- URL Parameters:
exchangeId(string, required): The exchange ID of the data file (e.g., "binance").symbol(string, required): The trading symbol. Use a dash (-) as a separator for URL safety (e.g., "BTC-USDT").timeframe(string, required): The timeframe of the data file (e.g., "1h", "1d").
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
{ "filePath": "/app/data/market/binance/BTC_USDT/1d.stchx", "fileSize": 48064, "header": { "magic": "STCHXBF1", "version": 1, "headerLength": 64, "recordLength": 48, "tsFormat": 1, "ohlcvFormat": 1, "numRecords": 1000, "symbol": "BTC/USDT", "timeframe": "1d" }, "sample": { "head": [ { "timestamp": 1672531200, "utc": "2023-01-01 00:00:00", "open": 16541.77, "high": 16630.43, "low": 16499.0, "close": 16603.24, "volume": 145339.71 } ], "tail": [ { "timestamp": 1758998400, "utc": "2025-09-26 00:00:00", "open": 85000.0, "high": 86000.0, "low": 84000.0, "close": 85500.0, "volume": 200000.0 } ] }, "validation": { "status": "passed", "message": "Data appears consistent.", "gaps": [], "duplicates": [], "outOfOrder": [] } } - Error Responses:
404 Not Found: If the requested data file does not exist.500 Internal Server Error: For any other processing errors.
- Description: Inspects a specific market data file (
-
GET /api/data/symbols/{exchangeId}- Description: Fetches a list of all available and active futures/swap symbols for a given exchange. This can be used to populate a symbol selection UI.
- Requires: None
- URL Parameters:
exchangeId(string, required): The exchange ID to query (e.g., "binance", "okx").
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
[ "1000PEPE/USDT:USDT", "ADA/USDT:USDT", "AVAX/USDT:USDT", "BCH/USDT:USDT", "BTC/USDT:USDT", "DOGE/USDT:USDT", "DOT/USDT:USDT", "ETH/USDT:USDT", "LINK/USDT:USDT", "LTC/USDT:USDT", "MATIC/USDT:USDT", "SOL/USDT:USDT", "XRP/USDT:USDT" ] - Error Responses:
400 Bad Request: If the exchange ID is not supported or if there's an error communicating with the exchange.
-
POST /api/backtests- Description: Queues a new backtest run for asynchronous execution. Returns a unique
runIdimmediately, which can be used to listen for real-time progress updates via Mercure. - Requires: None
- Request Body: (
Stochastix\Domain\Backtesting\Dto\LaunchBacktestRequestDto)strategyAlias(string, required): The alias of the strategy to run.symbols(string[], required): An array of symbols to run the backtest on (currently UI sends one).timeframe(string, required): The timeframe to use (e.g., "5m", "1d").initialCapital(string, required): The starting capital for the portfolio, as a string.dataSourceExchangeId(string, optional): The exchange to use for data. If omitted, the server's default is used.startDate(string, optional,YYYY-MM-DD): The start date. Ifnull, the backtest starts from the beginning of available data.endDate(string, optional,YYYY-MM-DD): The end date. Ifnull, the backtest runs to the end of available data.inputs(object, optional): A key-value map of the strategy-specific inputs.commissionConfig(object, optional): Configuration for commission.
- Example Request Body:
{ "strategyAlias": "sample_strategy", "symbols": ["ETH/USDT"], "timeframe": "5m", "initialCapital": "50000", "dataSourceExchangeId": "okx", "startDate": "2025-02-01", "endDate": "2025-03-01", "inputs": { "emaShortPeriod": 10, "emaLongPeriod": 21 } } - Success Response:
202 Accepted - Example Success Response Body:
{ "status": "queued", "backtestRunId": "btrun_6662d5119b91c7.73453396" } - Error Responses:
400 Bad Request: Invalid input (validation errors in the request body).500 Internal Server Error: If the message could not be dispatched.
- Description: Queues a new backtest run for asynchronous execution. Returns a unique
-
GET /api/backtests- Description: Retrieves a list of all previously completed and saved backtest runs, sorted with the most recent first. Provides metadata parsed from filenames.
- Requires: None
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
[ { "runId": "20250607-083000_sample_strategy_a1b2c3", "timestamp": 1749285000, "strategyAlias": "sample_strategy" }, { "runId": "20250606-140037_sample_strategy_d4e5f6", "timestamp": 1749201637, "strategyAlias": "sample_strategy" } ] - Error Responses:
500 Internal Server Error.
-
GET /api/backtests/{runId}- Description: Fetches the full, detailed result JSON file for a single completed backtest run. The response includes the backtest configuration, the full trade log, a list of any trades still open at the end of the run, and a comprehensive, pre-calculated statistics object.
- Requires: None
- URL Parameters:
runId(string, required): The unique ID of the backtest run.
- Request Body: None
- Success Response:
200 OK - Example Success Response Body:
{ "status": "Backtest completed. Processed 8640 bars across 1 symbols.", "config": { "strategyAlias": "sample_strategy", "strategyClass": "App\\Strategy\\SampleStrategy", "symbols": ["ETH/USDT"], "timeframe": "5m", "startDate": "2025-02-01T00:00:00+00:00", "endDate": "2025-03-01T00:00:00+00:00", "initialCapital": "50000", "commissionConfig": { "type": "percentage", "rate": "0.001" }, "strategyInputs": { "emaShortPeriod": 10, "emaLongPeriod": 21 } }, "finalCapital": "51260.75", "closedTrades": [ { "tradeNumber": 1, "symbol": "ETH/USDT", "direction": "long", "entryPrice": "3000.00", "exitPrice": "3150.50", "quantity": "0.83333333", "entryTime": "2025-02-02 10:00:00", "exitTime": "2025-02-03 14:20:00", "pnl": "124.87", "entryCommission": "1.25", "exitCommission": "1.31", "enterTags": ["ema_crossover_long"], "exitTags": ["exit_signal"] } ], "openPositions": [ { "symbol": "ETH/USDT", "direction": "long", "quantity": "0.50000000", "entryPrice": "3100.00000", "entryTime": "2025-02-28 11:30:00", "currentPrice": "3120.00000", "unrealizedPnl": "10.00" } ], "statistics": { "pairStats": [ { "label": "ETH/USDT", "trades": 48, "averageProfitPercentage": 0.051, "totalProfit": 1250.75, "totalProfitPercentage": 2.5, "avgDurationMin": 180, "wins": 30, "draws": 0, "losses": 18 } ], "enterTagStats": [ { "label": "ema_crossover_long", "trades": 24, "averageProfitPercentage": 0.12, "totalProfit": 800.50, "totalProfitPercentage": 1.6, "avgDurationMin": 200, "wins": 20, "draws": 0, "losses": 4 } ], "exitTagStats": [ { "label": "exit_signal", "trades": 30, "averageProfitPercentage": 0.08, "totalProfit": 950.00, "totalProfitPercentage": 1.9, "avgDurationMin": 190, "wins": 25, "draws": 0, "losses": 5 }, { "label": "stop_loss", "trades": 18, "averageProfitPercentage": -0.02, "totalProfit": -300.75, "totalProfitPercentage": -0.6, "avgDurationMin": 160, "wins": 5, "draws": 0, "losses": 13 } ], "summaryMetrics": { "backtestingFrom": "2025-02-01 00:00:00", "backtestingTo": "2025-03-01 00:00:00", "maxOpenTrades": 1, "totalTrades": 48, "dailyAvgTrades": 1.71, "startingBalance": 50000, "finalBalance": 51260.75, "balanceCurrency": "USDT", "absProfit": 1260.75, "totalProfitPercentage": 2.52, "profitFactor": 2.1, "sharpe": 1.89, "sortino": 2.4, "calmar": 1.2, "cagrPercentage": 34.5, "expectancy": 26.05, "expectancyRatio": 1.5, "avgDurationWinnersMin": 200, "avgDurationLosersMin": 160, "maxConsecutiveWins": 5, "maxConsecutiveLosses": 3, "maxAccountUnderwaterPercentage": 1.5, "absoluteDrawdown": 750.00, "marketChangePercentage": 5.2 } } } - Error Responses:
404 Not Found: If no result file exists for the givenrunId.500 Internal Server Error.
GET /api/chart-data/{runId}- Description: Fetches the OHLCV (candlestick) data, closed trades, open positions, and indicator data required to render a chart for a specific backtest run. Supports pagination for handling large datasets.
- Requires: None
- URL Parameters:
runId(string, required): The unique ID of the backtest run.
- Query Parameters:
fromTimestamp(integer, optional): Unix timestamp for the start of the desired data range.toTimestamp(integer, optional): Unix timestamp for the end of the desired data range.countback(integer, optional): The number of candles to fetch counting back fromtoTimestamp(or from the end of the backtest iftoTimestampis not provided).
- Success Response:
200 OK - Example Success Response Body:
{ "ohlcv": [ { "time": 1738454400, "open": 2999.5, "high": 3005.0, "low": 2998.0, "close": 3000.0 }, { "time": 1738454700, "open": 3000.0, "high": 3008.0, "low": 2999.0, "close": 3007.5 } ], "trades": [ { "direction": "long", "quantity": "1.000000", "entryTime": 1738368000, "entryPrice": "2950.00", "exitTime": 1738454400, "exitPrice": "3000.00", "pnl": "50.00" } ], "openPositions": [ { "direction": "short", "quantity": "0.5", "entryTime": 1738454700, "entryPrice": "3007.50", "currentPrice": "3007.50", "unrealizedPnl": "0.00" } ], "indicators": { "ema_fast": { "metadata": { "name": "Fast EMA", "overlay": true, "plots": [{"key": "value", "type": "line", "color": null}], "annotations": [] }, "data": { "value": [ { "time": 1738454400, "value": 2998.5 }, { "time": 1738454700, "value": 3001.0 } ] } } } } - Error Responses:
404 Not Found: If therunIdis invalid or if the required market data file is missing.400 Bad Request: If the backtest configuration is malformed or query parameters are invalid.500 Internal Server Error.
This family of endpoints provides access to the raw, high-resolution time-series data calculated at the end of a backtest run, suitable for rendering detailed performance charts.
GET /api/plots/{metric}/{runId}- Description: Fetches a specific time-series data plot (like the mark-to-market equity curve) for a given backtest run.
- Requires: None
- URL Parameters:
metric(string, required): The name of the metric series to fetch. Currently supported:equity.runId(string, required): The unique ID of the backtest run.
- Request Body: None
- Success Response:
200 OK - Example Success Response Body (for
/api/plots/equity/some_run_id):{ "data": [ { "time": 1704067200, "value": 10000.0 }, { "time": 1704153600, "value": 10000.0 }, { "time": 1704240000, "value": 9920.0 }, { "time": 1704326400, "value": 10040.0 } ] } - Error Responses:
404 Not Found: If therunIdis invalid or if the requested{metric}plot does not exist for that run.500 Internal Server Error.