The Prices response now uses typed Price objects instead of parallel arrays.
// Before (v1.0.x)
for ($i = 0; $i < count($prices->symbols); $i++) {
echo $prices->symbols[$i] . ": $" . $prices->mid[$i];
}
// After (v1.1.0)
foreach ($prices->prices as $price) {
echo $price->symbol . ": $" . $price->mid;
}Removed properties: $symbols, $mid, $change, $changepct, $updated arrays
Added property: $prices array of Price objects
Migration: Change $prices->symbols[$i] to $prices->prices[$i]->symbol, and similarly for other fields.
The News response now returns ALL articles from the API instead of only the first one. Uses typed Article objects.
// Before (v1.0.x)
echo $news->headline;
echo $news->symbol;
// After (v1.1.0)
foreach ($news->articles as $article) {
echo $article->headline;
echo $article->symbol;
}Removed properties: $symbol, $headline, $content, $source, $publication_date flat properties
Added property: $articles array of Article objects
Bug fix: The News endpoint previously only returned the first article from the API. It now returns ALL articles.
Migration: Change $news->headline to $news->articles[0]->headline, and similarly for other fields.
- New
Priceclass (src/Endpoints/Responses/Stocks/Price.php) for individual stock price data - New
Articleclass (src/Endpoints/Responses/Stocks/Article.php) for individual news article data
🎉 First Stable Release - Production-ready PHP SDK for Market Data API with full feature parity with the Python SDK.
- PHP 8.2+ Required - Modern PHP with strict typing
- 100% Test Coverage - Comprehensive unit and integration tests across PHP 8.2, 8.3, 8.4, and 8.5
- Full Feature Parity - Complete feature parity with the official Python SDK
- Production Ready - Battle-tested with automatic retry, rate limiting, and comprehensive logging
- 50+ Bug Fixes - Extensive testing and fixes for edge cases, error handling, and API compatibility
- Minimum PHP version is now 8.2 (was 8.1 in v0.6.x)
The bulkQuotes() method has been removed. Use quotes() instead, which now supports multiple symbols.
// Before (v0.6.x)
$bulkQuotes = $client->stocks->bulkQuotes(['AAPL', 'MSFT']);
// After (v1.0.0)
$quotes = $client->stocks->quotes(['AAPL', 'MSFT']);The Quote and OptionChainStrike classes have been consolidated into a single OptionQuote class:
// Before (v0.6.x)
use MarketDataApp\Endpoints\Responses\Options\Quote;
use MarketDataApp\Endpoints\Responses\Options\OptionChainStrike;
// After (v1.0.0)
use MarketDataApp\Endpoints\Responses\Options\OptionQuote;- Token parameter is now optional (auto-resolves from
MARKETDATA_TOKENenv var or.envfile) - Invalid tokens now throw
UnauthorizedExceptionduring construction (not on first API call) - New optional
$loggerparameter for custom PSR-3 logger injection
// Token auto-resolution (new in v1.0.0)
$client = new Client(); // Reads from MARKETDATA_TOKEN env var
// Token validation is now immediate
try {
$client = new Client('invalid_token');
} catch (UnauthorizedException $e) {
echo "Invalid token";
}- Renamed
min_bid_ask_spreadtomax_bid_ask_spread- The previous parameter name was incorrect and silently ignored by the API - Removed default
expiration=all- No longer sends a default expiration filter - Removed default
nonstandard=true- Non-standard contracts are no longer included by default - Changed
deltaparameter type tostring- Now accepts range expressions like"0.3-0.5"
- Changed
strikeparameter type toint|float- Now accepts decimal strikes like12.5for non-standard options
The following parameters were present in v0.6.x but were never supported by the API (silently ignored):
- Candles: Removed
exchange,country,adjust_dividendsparameters fromcandles(),bulkCandles(), and concurrent candle methods - Earnings: Removed
datekeyparameter fromearnings()
Comprehensive logging with configurable levels:
// Configure via environment variable
putenv('MARKETDATA_LOGGING_LEVEL=DEBUG');
$client = new Client();
// Or inject custom PSR-3 logger (Monolog, Laravel, etc.)
$client = new Client(logger: $customLogger);Log levels: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY
Rate limits are automatically tracked and accessible after each request:
$quote = $client->stocks->quote('AAPL');
echo $client->rate_limits->remaining; // Credits remaining
echo $client->rate_limits->limit; // Total credits
echo $client->rate_limits->reset; // Carbon datetime of reset
echo $client->rate_limits->consumed; // Credits used in last requestBuilt-in retry logic for transient failures:
- 3 retry attempts maximum
- Exponential backoff (0.5s - 5s)
- Only retries on 5xx server errors
- Checks API service status before retrying
More specific exception handling:
use MarketDataApp\Exceptions\UnauthorizedException; // 401 errors
use MarketDataApp\Exceptions\BadStatusCodeError; // Other 4xx errors
use MarketDataApp\Exceptions\RequestError; // Network errors
try {
$client = new Client($token);
$quote = $client->stocks->quote('AAPL');
} catch (UnauthorizedException $e) {
// Invalid or expired token
} catch (BadStatusCodeError $e) {
// Other client errors (400, 403, 404, etc.)
} catch (RequestError $e) {
// Network errors, timeouts
}All SDK exceptions now provide first-class access to request context, making it easier to gather information for support tickets:
try {
$quote = $client->stocks->quote('AAPL');
} catch (MarketDataException $e) {
// One-liner for support tickets - ready to copy/paste!
echo $e->getSupportInfo();
// Or get structured data for logging systems
$logger->error('API Error', $e->getSupportContext());
}New convenience methods:
getSupportInfo()- Returns a pre-formatted string ready to paste into support ticketsgetSupportContext()- Returns an array with all context (perfect for JSON logging)
Individual property accessors:
getRequestId()- Cloudflare request ID (cf-ray header)getRequestUrl()- Full URL that was requestedgetTimestamp()-DateTimeImmutablein UTC (convert to your timezone as needed)getResponse()- Raw PSR-7 response object- Enhanced
__toString()now includes timestamp, request ID, and URL
Note: getSupportInfo() and getSupportContext() automatically convert timestamps to America/New_York to match API logs for support tickets.
New base exception class:
MarketDataException- All SDK exceptions now extend this base class, allowing you to catch all SDK exceptions with a single catch block
See examples/error_handling.php for complete usage examples.
Stocks - prices(): Get SmartMid model prices for single or multiple symbols
$prices = $client->stocks->prices(['AAPL', 'MSFT']);Options - quotes() with multiple symbols: Concurrent fetching for multiple option symbols
$quotes = $client->options->quotes(['AAPL250117C00200000', 'AAPL250117P00200000']);Utilities - user(): Get user account information
$user = $client->utilities->user();New Settings class with .env file support:
# .env file
MARKETDATA_TOKEN=your_token_here
MARKETDATA_OUTPUT_FORMAT=JSON
MARKETDATA_LOGGING_LEVEL=INFO
MARKETDATA_MODE=LIVEControl the maximum acceptable age for cached data when using mode=CACHED:
use MarketDataApp\Enums\Mode;
use MarketDataApp\Endpoints\Requests\Parameters;
// Accept cached data up to 5 minutes old
$params = new Parameters(mode: Mode::CACHED, maxage: 300);
$quote = $client->stocks->quote('AAPL', parameters: $params);
// Also accepts DateInterval or CarbonInterval
$params = new Parameters(mode: Mode::CACHED, maxage: new DateInterval('PT5M'));If cached data is older than maxage, the API returns 204 (no content) with no credit charge, enabling cost-efficient fallback strategies.
New extended parameter on quote(), quotes(), and prices() methods:
// Get primary session quote only (no extended hours)
$quote = $client->stocks->quote('AAPL', extended: false);
// Default is extended: true (includes extended hours when available)
$quote = $client->stocks->quote('AAPL');New am and pm parameters on option_chain() for filtering index options by settlement type:
// Get only AM-settled SPX options
$chain = $client->options->option_chain('SPX', am: true);
// Get only PM-settled SPXW options
$chain = $client->options->option_chain('SPX', pm: true);ApiStatusResult- Service status (ONLINE, OFFLINE, UNKNOWN)DateFormat- CSV date formatting (TIMESTAMP, UNIX, SPREADSHEET)Mode- Data feed mode (LIVE, CACHED, DELAYED)
- All response objects implement
__toString()for human-readable output - New
FormatsForDisplaytrait for formatting currency, percentages, volumes - New
ValidatesInputstrait for input validation
- Up to 50 concurrent requests for bulk operations
- Automatic date range splitting for large intraday candle requests
- Concurrent fetching for multi-symbol options quotes
$chain = $client->options->option_chain('AAPL', expiration: '2025-01-17');
$chain->toQuotes(); // Flatten to Quotes object
$chain->getAllQuotes(); // Get all quotes as array
$chain->getExpirationDates(); // Get expiration dates
$chain->getQuotesByExpiration($date); // Filter by expiration
$chain->getCalls(); // Get call options only
$chain->getPuts(); // Get put options only
$chain->getByStrike(200.0); // Filter by strike
$chain->getStrikes(); // Get all strike prices
$chain->count(); // Total quote count- Update PHP version to 8.2 or higher
- Replace
bulkQuotes()withquotes()for multi-symbol stock quotes - Update Options imports - use
OptionQuoteinstead ofQuoteorOptionChainStrike - Update exception handling - catch
UnauthorizedExceptionduring client construction - Update
option_chain()calls:- Rename
min_bid_ask_spreadtomax_bid_ask_spread - Remove reliance on default
expiration=allandnonstandard=trueif you were depending on them - Update
deltavalues to strings if using range expressions
- Rename
- Remove unsupported parameters - if you were passing
exchange,country,adjust_dividendsto candles ordatekeyto earnings, remove them (they were silently ignored) - Update dependencies:
composer update
New required dependencies:
psr/log: ^3.0- PSR-3 logging interfacevlucas/phpdotenv: ^5.5- Environment file support
Updated development dependencies:
phpunit/phpunit: ^11.5.50(was ^10.3.2)
This release includes 50+ bug fixes addressing:
- CSV/HTML format handling and error detection
- Empty array and missing field guards across all response types
- Date parsing and automatic date range splitting for large requests
- Symbol whitespace trimming and URL encoding
- Boolean parameter encoding for API compatibility
- Endpoint URL construction and trailing slashes
- Concurrent request error handling and partial failure tolerance
Added universal parameters to all endpoints with the ability to change format to CSV and HTML (beta).
Minor improvements and bug fixes.
Update options->option_chain to use enum values rather than the enum itself.
Small bug fixes found from initial beta test
- Typo fixed Range::OUT_THE_MONEY > Range::OUT_OF_THE_MONEY
- Corrected stocks->quotes() endpoint url
- Changes OptionChain response to group strikes under expiration date
This library is now in beta. Feel free to try it out and report any bugs you find back here.
- Added integration tests for all endpoints except Market (unavailable)
- Added more tests for more complete code coverage
- Tweaks to data structures based on results of integration test
- Changed all Carbon date endpoints to receive a string rather than a Carbon instance.
- Completed remaining endpoints:
- Options
- expirations
- lookup
- strikes
- option_chain
- quotes
- Utilities
- api_status
- headers
- Mutual Funds
- candles
- Markets
- status
- Options
- Completed Stocks endpoints: earnings, news.
- Add stubs for the rest of the endpoints.
- Added Stocks endpoints: quote, quotes, bulkQuotes, candles, bulkCandles.
- Added custom ApiException class to handle status = 'error' messages.
- Moved Responses to new directory.
- Initial release.