Thanks to visit codestin.com
Credit goes to github.com

Skip to content

WioEX/wioex-php-sdk

Repository files navigation

WioEX PHP SDK

Official PHP SDK for WioEX Financial Data API - Enterprise-grade client library for accessing stocks, trading signals, news, currency, and financial market data.

PHP Version Latest Version License Tests

What's New in v2.9.0

Enhanced Configuration Management & Enterprise-Grade Type Safety.

πŸ”§ v2.9.0 - Configuration & Type Safety Release

  • Enhanced Configuration Management: New dot notation support for complex configuration access (config.cache.redis.host)
  • Advanced Type Safety: PHPStan Level 8 compliance with comprehensive null safety improvements
  • Improved Cache Management: Enhanced cache drivers with proper type declarations and macro support
  • Null Safety: Comprehensive null-safe operations throughout the SDK for enterprise reliability
  • Method Signature Improvements: All public methods now have proper return type declarations
  • Validation Enhancements: Improved validation with strict comparison operators and type checking

Continued Excellence from v2.8.x

  • API Route Optimization: Improved endpoint routing and request handling
  • Comprehensive Ticker Analysis: Complete stock analysis combining analyst ratings, earnings insights, insider activity, news sentiment, and options analysis
  • Investment Research Grade: Institutional-quality data for professional portfolio management
  • 15+ Helper Methods: Structured access to all analysis sections with type-safe methods
  • Portfolio Support: Analyze multiple stocks efficiently for portfolio research

Built on v2.7.x Foundation

  • Unified ResponseTemplate Support: Standardized response format across all WioEX API endpoints
  • Enhanced Stock Data: Institutional-grade integration with pre/post market data, 52-week ranges, market cap, and company logos
  • Advanced Type Safety: Complete PHPStan compliance with comprehensive array type specifications
  • Enhanced Metadata Access: 20+ new helper methods for accessing response metadata and performance metrics
  • Detailed Mode Support: Enhanced stocks endpoint with extended market data and institutional-grade accuracy
  • Backward Compatibility: Full support for legacy response formats with automatic adaptation
  • Validation Schemas: Comprehensive validation schemas for all endpoint types
  • Professional Error Handling: Enhanced validation reporting and error management

Ideal for Professional Trading

  • Portfolio management for 1000+ stocks
  • Real-time market monitoring
  • High-frequency trading applications
  • Risk management systems

Requirements

  • PHP 8.1+
  • ext-json, ext-curl
  • Composer

Installation

composer require wioex/php-sdk

Quick Start

<?php

require 'vendor/autoload.php';

use Wioex\SDK\WioexClient;
use Wioex\SDK\Exceptions\{
 AuthenticationException,
 RateLimitException,
 WioexException
};

// Initialize client with configuration
$client = new WioexClient([
 'api_key' => 'your-api-key-here',
 'timeout' => 30,
 'retry' => [
 'times' => 3,
 'delay' => 100
 ]
]);

try {
 // 1. Enhanced stock quotes with unified ResponseTemplate format
 $response = $client->stocks()->quote('AAPL,GOOGL,MSFT');
 
 if ($response->successful()) {
 // Access unified metadata
 $metadata = $response->getWioexMetadata();
 $performance = $response->getPerformance();
 
 echo "Portfolio Update (Response Time: {$performance['total_time_ms']}ms):\n";
 
 // Use new unified instruments format
 foreach ($response->getInstruments() as $stock) {
 printf(
 "%-6s $%-8.2f %+.2f%% (Vol: %s)\n",
 $stock['symbol'],
 $stock['price']['current'],
 $stock['change']['percent'],
 number_format($stock['volume']['current'])
 );
 
 // Check for trading signals (auto-included)
 if (isset($stock['signal']) && $stock['signal']['confidence'] > 70) {
 echo "Signal: {$stock['signal']['signal_type']} (confidence: {$stock['signal']['confidence']}%)\n";
 }
 }
 echo "\n";
 }

 // 2. Check market status with detailed information
 $marketStatus = $client->markets()->status();
 $nyse = $marketStatus['markets']['nyse'];
 echo "Market Status:\n";
 echo "NYSE: " . ($nyse['is_open'] ? 'OPEN' : 'CLOSED') . "\n";
 echo "Trading Hours: {$nyse['hours']['regular']['open']} - {$nyse['hours']['regular']['close']}\n";
 echo "Next Session: {$nyse['next_session']}\n\n";

 // 3. Get top market movers
 $gainers = $client->screens()->gainers(5);
 echo "Top Gainers:\n";
 foreach ($gainers['data'] as $stock) {
 printf("%-6s +%.2f%%\n", $stock['symbol'], $stock['change_percent']);
 }
 echo "\n";

 // 4. Account information and usage
 $account = $client->account()->balance();
 echo "Account Status:\n";
 echo "Credits Remaining: {$account['credits']}\n";
 echo "Plan: {$account['plan']['name']}\n";
 echo "Reset Date: {$account['reset_date']}\n";

} catch (AuthenticationException $e) {
 echo "Authentication Error: {$e->getMessage()}\n";
 echo "Please check your API key.\n";
} catch (RateLimitException $e) {
 echo "Rate Limit Exceeded: {$e->getMessage()}\n";
 echo "Retry after: {$e->getRetryAfter()} seconds\n";
} catch (WioexException $e) {
 echo "API Error: {$e->getMessage()}\n";
}

// Example Response Structure for stocks()->quote():
/*
{
 "tickers": [
 {
 "ticker": "AAPL",
 "name": "Apple Inc.",
 "market": {
 "price": 175.43,
 "change": {
 "amount": 2.15,
 "percent": 1.24
 },
 "volume": 62547890,
 "market_cap": 2765432100000
 },
 "signal": {
 "signal_type": "buy",
 "confidence": 78,
 "generated_at": "2025-10-22T15:30:00Z"
 }
 }
 ],
 "metadata": {
 "count": 1,
 "processing_time": 45
 }
}
*/

Advanced Configuration

Enhanced Configuration Management with Dot Notation

The SDK now supports advanced configuration management with dot notation for easy access to nested configuration values:

use Wioex\SDK\WioexClient;

// Advanced client configuration with enhanced options
$client = new WioexClient([
    'api_key' => 'your-api-key-here',
    'timeout' => 30,
    'retry' => [
        'times' => 3,
        'delay' => 100
    ],
    'cache' => [
        'driver' => 'redis',
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => null,
            'database' => 0
        ],
        'ttl' => 300
    ],
    'debug' => [
        'enabled' => true,
        'log_requests' => true,
        'performance_tracking' => true
    ]
]);

// Access configuration values using dot notation
$redisHost = $client->getConfig()->get('cache.redis.host'); // '127.0.0.1'
$debugEnabled = $client->getConfig()->get('debug.enabled'); // true
$retryTimes = $client->getConfig()->get('retry.times'); // 3

// Set configuration values dynamically
$client->getConfig()->set('cache.redis.port', 6380);
$client->getConfig()->set('debug.performance_tracking', false);

// Check if configuration exists
if ($client->getConfig()->has('cache.redis.password')) {
    echo "Redis password is configured\n";
}

Type-Safe Configuration Access

All configuration methods now include proper type safety and null handling:

// Type-safe configuration with defaults
$timeout = $client->getConfig()->get('timeout', 30); // Returns 30 if not set
$cacheEnabled = $client->getConfig()->get('cache.enabled', false); // Boolean default
$debugLevel = $client->getConfig()->get('debug.level', 'info'); // String default

// Multiple configuration checks
if ($client->getConfig()->has('cache.redis') && 
    $client->getConfig()->get('cache.enabled', false)) {
    echo "Redis cache is properly configured and enabled\n";
}

Enhanced Cache Management

Improved cache management with macro support and better type declarations:

// Enhanced cache operations with type safety
$cache = $client->getCache();

// Remember pattern with type-safe callbacks
$expensiveData = $cache->remember('stock_analysis_AAPL', function() {
    return $this->performComplexAnalysis('AAPL');
}, 3600); // Cache for 1 hour

// Pull pattern (get and delete)
$temporaryData = $cache->pull('temp_calculation_key');

// Cache macros for custom functionality
$cache->macro('getOrFetch', function(string $key, callable $fetcher, int $ttl = 300) {
    return $this->remember($key, $fetcher, $ttl);
});

// Use custom macro
$marketData = $cache->getOrFetch('market_status', function() {
    return $this->client->markets()->status();
}, 600);

Core Features

Stock Data

use Wioex\SDK\Enums\TimelineInterval;
use Wioex\SDK\Enums\SortOrder;

// 1. Search stocks with response processing
$searchResults = $client->stocks()->search('technology');
echo "Found {$searchResults['metadata']['total']} tech stocks:\n";
foreach (array_slice($searchResults['data'], 0, 5) as $stock) {
 printf("%-6s %-30s %s\n", 
 $stock['symbol'], 
 $stock['name'], 
 $stock['exchange']
 );
}

// 2. Get quotes with comprehensive data processing
$portfolio = $client->stocks()->quote('AAPL,GOOGL,MSFT,TSLA');
echo "\nPortfolio Performance:\n";
$totalValue = 0;
foreach ($portfolio['tickers'] as $stock) {
 $marketValue = $stock['market']['price'] * 100; // Assuming 100 shares
 $totalValue += $marketValue;
 
 printf("%-6s $%-8.2f %+.2f%% Value: $%-10.2f\n",
 $stock['ticker'],
 $stock['market']['price'],
 $stock['market']['change']['percent'],
 $marketValue
 );
}
echo "Total Portfolio Value: $" . number_format($totalValue, 2) . "\n";

// 3. Historical data with ENUMs for type safety
$timeline = $client->stocks()->timeline('AAPL', [
 'interval' => TimelineInterval::ONE_DAY, // Type-safe ENUM usage
 'size' => 30,
 'orderBy' => SortOrder::DESCENDING
]);

echo "\nAAPL 30-Day Price History:\n";
$prices = [];
foreach ($timeline['data'] as $day) {
 printf("%s: $%-7.2f (Vol: %s)\n",
 $day['date'],
 $day['close'],
 number_format($day['volume'])
 );
 $prices[] = $day['close'];
}

// Calculate basic statistics
$avgPrice = array_sum($prices) / count($prices);
$maxPrice = max($prices);
$minPrice = min($prices);
echo "\nPrice Analysis:\n";
echo "Average: $" . number_format($avgPrice, 2) . "\n";
echo "Range: $" . number_format($minPrice, 2) . " - $" . number_format($maxPrice, 2) . "\n";

// 4. Company information with financial metrics
$companyInfo = $client->stocks()->info('AAPL');
echo "\nApple Inc. Company Profile:\n";
echo "Sector: {$companyInfo['sector']} | Industry: {$companyInfo['industry']}\n";
echo "Market Cap: $" . number_format($companyInfo['market_cap'] / 1000000000, 1) . "B\n";
echo "P/E Ratio: {$companyInfo['pe_ratio']}\n";
echo "52-Week Range: $" . number_format($companyInfo['week_52_low'], 2) . 
 " - $" . number_format($companyInfo['week_52_high'], 2) . "\n";

// 5. Price changes across multiple timeframes
$priceChanges = $client->stocks()->priceChanges('AAPL');
echo "\nAAPL Price Performance:\n";
foreach ($priceChanges['timeframes'] as $period => $change) {
 $indicator = $change['percent'] > 0 ? '' : '';
 printf("%s %-10s %+.2f%% ($%+.2f)\n",
 $indicator,
 strtoupper($period),
 $change['percent'],
 $change['amount']
 );
}

// 6. Bulk operations for portfolio analysis
$watchlist = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA', 'META', 'NVDA'];
$bulkQuotes = $client->stocks()->quoteBulk($watchlist, [
 'batch_size' => 3, // Process in batches to respect rate limits
 'delay_between_batches' => 100, // 100ms delay between batches
 'continue_on_error' => true // Continue processing if one fails
]);

echo "\nWatchlist Analysis:\n";
$gainers = $losers = 0;
foreach ($bulkQuotes['data'] as $symbol => $quote) {
 $change = $quote['market']['change']['percent'];
 if ($change > 0) $gainers++;
 else if ($change < 0) $losers++;
}

echo "Market Sentiment: {$gainers} gainers, {$losers} losers\n";
echo "Processing time: {$bulkQuotes['metadata']['processing_time']}ms\n";

// 7. Enhanced Stocks with Detailed Mode
$detailedResponse = $client->stocks()->quoteDetailed('SOUN');
$instruments = $detailedResponse->getInstruments();
$dataQuality = $detailedResponse->getDataQuality();

if (!empty($instruments)) {
    $stock = $instruments[0];
    echo "\nEnhanced Stock Data (Provider: {$dataQuality['data_accuracy']}):\n";
    echo "Symbol: {$stock['symbol']} ({$stock['name']})\n";
    echo "Current Price: $" . number_format($stock['price']['current'], 2) . "\n";
    echo "52W Range: $" . number_format($stock['price']['fifty_two_week_low'], 2) . 
         " - $" . number_format($stock['price']['fifty_two_week_high'], 2) . "\n";
    
    if (isset($stock['market_cap']['value'])) {
        $marketCapB = $stock['market_cap']['value'] / 1000000000;
        echo "Market Cap: $" . number_format($marketCapB, 2) . "B\n";
    }
    
    // Pre/Post market data
    if (isset($stock['pre_market']) && $stock['pre_market']['price'] > 0) {
        echo "Pre-Market: $" . number_format($stock['pre_market']['price'], 2) . 
             " (" . sprintf("%+.2f%%", $stock['pre_market']['change_percent']) . ")\n";
    }
}

// 8. Response Validation
$validation = $detailedResponse->validateEnhancedStockQuote();
if ($validation->isValid()) {
    echo "βœ… Enhanced stock quote validation: PASSED\n";
} else {
    echo "❌ Validation errors found\n";
    foreach ($validation->getErrors() as $error) {
        echo "  - {$error['message']}\n";
    }
}

Enhanced Response Structure (Unified ResponseTemplate):

// Enhanced stocks()->quoteDetailed() response:
{
  "metadata": {
    "wioex": {
      "api_version": "2.0",
      "brand": "WioEX Financial Data API",
      "website": "https://wioex.com"
    },
    "response": {
      "timestamp_utc": "2025-10-23T14:30:00Z",
      "request_id": "wioex_20251023_143000_abc123",
      "response_time_ms": 245.67
    },
    "credits": {
      "consumed": 1.0,
      "remaining_balance": 4999.0
    },
    "data_quality": {
      "data_freshness": "real_time",
      "data_accuracy": "institutional_grade"
    },
    "performance": {
      "total_time_ms": 245.67,
      "server_region": "us-east-1"
    }
  },
  "data": {
    "total_symbols_requested": 1,
    "total_symbols_returned": 1,
    "market_timezone": "America/New_York",
    "data_provider": "enhanced_institutional_grade",
    "data_level": "detailed",
    "instruments": [
      {
        "symbol": "SOUN",
        "name": "SoundHound AI, Inc.",
        "type": "stock",
        "currency": "USD",
        "exchange": "NASDAQ",
        "price": {
          "current": 5.47,
          "open": 5.35,
          "previous_close": 5.42,
          "day_high": 5.62,
          "day_low": 5.31,
          "fifty_two_week_high": 10.25,
          "fifty_two_week_low": 1.12
        },
        "change": {
          "amount": 0.05,
          "percent": 0.92
        },
        "volume": {
          "current": 2547890,
          "average": 3200000
        },
        "market_cap": {
          "value": 890000000
        },
        "pre_market": {
          "price": 5.52,
          "change": 0.10,
          "change_percent": 1.84
        },
        "company_info": {
          "logo_url": "https://logo.clearbit.com/soundhound.com"
        },
        "market_status": {
          "is_open": true,
          "session": "regular",
          "real_time": true
        }
      }
    ]
  }
}

New Metadata Access Methods

The SDK now provides 20+ helper methods to easily access response metadata and performance metrics:

// Response metadata access
$response = $client->stocks()->quoteDetailed('AAPL');

// WioEX branding and API info
$wioexInfo = $response->getWioexMetadata();
echo "API Version: {$wioexInfo['api_version']}\n";
echo "Brand: {$wioexInfo['brand']}\n";

// Performance metrics
$performance = $response->getPerformance();
echo "Response Time: {$performance['total_time_ms']}ms\n";
echo "Server Region: {$performance['server_region']}\n";

// Credit usage
$credits = $response->getCredits();
echo "Credits Consumed: {$credits['consumed']}\n";
echo "Remaining Balance: {$credits['remaining_balance']}\n";

// Data quality indicators
$dataQuality = $response->getDataQuality();
echo "Data Freshness: {$dataQuality['data_freshness']}\n";
echo "Data Accuracy: {$dataQuality['data_accuracy']}\n";

// Request information
$requestId = $response->getRequestId();
$responseTime = $response->getResponseTime();
echo "Request ID: {$requestId}\n";
echo "Total Time: {$responseTime}ms\n";

// Enhanced data checks
if ($response->hasEnhancedData()) {
    echo "βœ… Enhanced pre/post market data available\n";
    $extendedHours = $response->getExtendedHoursData();
    foreach ($extendedHours as $stock) {
        echo "Pre-market: \${$stock['pre_market']['price']}\n";
    }
}

// Validation
$validation = $response->validateEnhancedStockQuote();
if ($validation->isValid()) {
    echo "βœ… Response validation passed\n";
} else {
    echo "❌ Validation errors:\n";
    foreach ($validation->getErrors() as $error) {
        echo "  - {$error['message']}\n";
    }
}

Backward Compatibility

The SDK automatically handles both new unified ResponseTemplate format and legacy formats:

// Works with both unified and legacy formats
$response = $client->stocks()->quote('AAPL');
$instruments = $response->getInstruments(); // Automatically adapts legacy 'tickers' to 'instruments'

// Check format type
if ($response->isUnifiedFormat()) {
    echo "Using new unified ResponseTemplate format\n";
} else {
    echo "Using legacy format (automatically adapted)\n";
}

// Get legacy-compatible data if needed
$legacyData = $response->getLegacyCompatibleData();

Market Screens

use Wioex\SDK\Enums\{ScreenType, MarketIndex, SortOrder};

// 1. Daily market movers analysis
$topGainers = $client->screens()->gainers(10);
echo "Top 10 Gainers Today:\n";
$totalGainerValue = 0;
foreach ($topGainers['data'] as $stock) {
 $marketCap = $stock['market_cap'] ?? 0;
 $totalGainerValue += $marketCap;
 
 printf("%-6s %+.2f%% $%-8.2f (Cap: $%.1fB)\n",
 $stock['symbol'],
 $stock['change_percent'],
 $stock['price'],
 $marketCap / 1000000000
 );
}

$topLosers = $client->screens()->losers(10);
echo "\n Top 10 Losers Today:\n";
foreach ($topLosers['data'] as $stock) {
 printf("%-6s %.2f%% $%-8.2f\n",
 $stock['symbol'],
 $stock['change_percent'],
 $stock['price']
 );
}

// 2. Volume analysis with enhanced parameters
$mostActive = $client->screens()->active(
 limit: 15,
 sortOrder: SortOrder::DESCENDING,
 market: MarketIndex::SP500 // Focus on S&P 500 stocks
);

echo "\n Most Active S&P 500 Stocks:\n";
$totalVolume = 0;
foreach ($mostActive['data'] as $stock) {
 $volume = $stock['volume'];
 $totalVolume += $volume;
 $avgVolume = $stock['average_volume'] ?? $volume;
 $volumeRatio = $avgVolume > 0 ? ($volume / $avgVolume) : 1;
 
 printf("%-6s Vol: %-12s (%.1fx avg)\n",
 $stock['symbol'],
 number_format($volume),
 $volumeRatio
 );
}
echo "Total Volume: " . number_format($totalVolume) . " shares\n";

// 3. Pre-market and after-hours analysis
$preMarketGainers = $client->screens()->preMarketGainers(5);
echo "\n Pre-Market Leaders:\n";
foreach ($preMarketGainers['data'] as $stock) {
 printf("%-6s %+.2f%% $%-8.2f (Vol: %s)\n",
 $stock['symbol'],
 $stock['change_percent'],
 $stock['price'],
 number_format($stock['volume'])
 );
}

$afterHoursLosers = $client->screens()->postMarketLosers(5);
echo "\n After-Hours Decliners:\n";
foreach ($afterHoursLosers['data'] as $stock) {
 printf("%-6s %.2f%% $%-8.2f\n",
 $stock['symbol'],
 $stock['change_percent'],
 $stock['price']
 );
}

// 4. IPO tracking and analysis
$upcomingIpos = $client->screens()->ipos('upcoming');
echo "\n Upcoming IPOs:\n";
foreach ($upcomingIpos['data'] as $ipo) {
 $priceRange = isset($ipo['price_range']) 
 ? "{$ipo['price_range']['low']}-{$ipo['price_range']['high']}"
 : "TBD";
 
 printf("%-20s %s $%s (%s)\n",
 $ipo['company_name'],
 $ipo['expected_date'],
 $priceRange,
 $ipo['exchange']
 );
}

$recentIpos = $client->screens()->ipos('recent', ['days' => 30]);
echo "\nRecent IPOs (Last 30 days): " . count($recentIpos['data']) . " offerings\n";

// 5. Advanced screening with unified method
$customScreen = $client->screens()->screen(ScreenType::GAINERS, [
 'min_price' => 10, // Stocks above $10
 'max_price' => 100, // Below $100
 'min_volume' => 1000000, // High volume
 'market_cap_min' => 1000000000, // $1B+ market cap
 'limit' => 20
]);

echo "\n Custom Screen (High-volume mid-caps):\n";
$qualifyingStocks = 0;
foreach ($customScreen['data'] as $stock) {
 if ($stock['change_percent'] > 3) { // Additional filter
 $qualifyingStocks++;
 printf("%-6s %+.2f%% $%-8.2f\n",
 $stock['symbol'],
 $stock['change_percent'],
 $stock['price']
 );
 }
}
echo "Qualifying stocks: {$qualifyingStocks}\n";

// 6. Market sentiment analysis
$marketSentiment = $client->screens()->marketSentiment(MarketIndex::NASDAQ, 30);
echo "\n NASDAQ Market Sentiment (30 days):\n";
echo "Overall: {$marketSentiment['data']['sentiment']}\n";
echo "Bullish: {$marketSentiment['data']['metrics']['bullish_ratio']}%\n";
echo "Bearish: {$marketSentiment['data']['metrics']['bearish_ratio']}%\n";
echo "Neutral: {$marketSentiment['data']['metrics']['neutral_ratio']}%\n";

// 7. Sector rotation analysis
$sectorPerformance = $client->screens()->sectorPerformance();
echo "\n Sector Performance Today:\n";
usort($sectorPerformance['data'], fn($a, $b) => $b['change_percent'] <=> $a['change_percent']);

foreach (array_slice($sectorPerformance['data'], 0, 5) as $sector) {
 $indicator = $sector['change_percent'] > 0 ? '' : '';
 printf("%s %-20s %+.2f%%\n",
 $indicator,
 $sector['sector'],
 $sector['change_percent']
 );
}

Response Structure Examples:

// screens()->gainers() response:
{
 "data": [
 {
 "symbol": "NVDA",
 "name": "NVIDIA Corp",
 "price": 485.20,
 "change_percent": 8.45,
 "change_amount": 37.82,
 "volume": 45670234,
 "market_cap": 1234567890000,
 "sector": "Technology"
 }
 ],
 "metadata": {
 "count": 10,
 "market_session": "regular",
 "generated_at": "2025-10-22T16:00:00Z"
 }
}

// screens()->marketSentiment() response:
{
 "data": {
 "sentiment": "bullish",
 "metrics": {
 "bullish_ratio": 65.4,
 "bearish_ratio": 23.1,
 "neutral_ratio": 11.5
 },
 "analysis_period": 30,
 "market_index": "nasdaq"
 }
}

Trading Signals

use Wioex\SDK\Enums\SignalType;

// 1. Active signals analysis with confidence filtering
$activeSignals = $client->signals()->active([
 'min_confidence' => 70,
 'limit' => 20
]);

echo "High-Confidence Trading Signals:\n";
$buySignals = $sellSignals = $holdSignals = 0;
$totalConfidence = 0;

foreach ($activeSignals['data'] as $signal) {
 $confidence = $signal['confidence'];
 $totalConfidence += $confidence;
 
 $emoji = match($signal['signal_type']) {
 'buy' => '',
 'sell' => '',
 'hold' => '',
 default => ''
 };
 
 printf("%s %-6s %-4s %d%% $%-8.2f (Target: $%.2f)\n",
 $emoji,
 $signal['symbol'],
 strtoupper($signal['signal_type']),
 $confidence,
 $signal['current_price'],
 $signal['target_price'] ?? 0
 );
 
 // Count signals by type
 match($signal['signal_type']) {
 'buy' => $buySignals++,
 'sell' => $sellSignals++,
 'hold' => $holdSignals++,
 default => null
 };
}

$avgConfidence = count($activeSignals['data']) > 0 
 ? $totalConfidence / count($activeSignals['data']) 
 : 0;

echo "\nSignal Summary:\n";
echo "Buy: {$buySignals} | Sell: {$sellSignals} | Hold: {$holdSignals}\n";
echo "Average Confidence: " . number_format($avgConfidence, 1) . "%\n\n";

// 2. Symbol-specific signal analysis
$portfolioSymbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA'];
foreach ($portfolioSymbols as $symbol) {
 $symbolSignals = $client->signals()->active([
 'symbol' => $symbol,
 'min_confidence' => 60
 ]);
 
 if (!empty($symbolSignals['data'])) {
 $signal = $symbolSignals['data'][0]; // Most recent signal
 echo "{$symbol} Analysis:\n";
 echo "Current Signal: " . strtoupper($signal['signal_type']) . "\n";
 echo "Confidence: {$signal['confidence']}%\n";
 echo "Price: \${$signal['current_price']}\n";
 
 if (isset($signal['reasoning'])) {
 echo "Reasoning: {$signal['reasoning']}\n";
 }
 
 // Risk assessment
 $riskLevel = match(true) {
 $signal['confidence'] >= 85 => 'Low',
 $signal['confidence'] >= 70 => 'Medium',
 default => 'High'
 };
 echo "Risk Level: {$riskLevel}\n\n";
 }
}

// 3. Signal history and performance analysis
$signalHistory = $client->signals()->history([
 'days' => 30,
 'include_performance' => true
]);

echo "Signal Performance (Last 30 days):\n";
$totalSignals = count($signalHistory['data']);
$successfulSignals = array_filter($signalHistory['data'], 
 fn($s) => ($s['performance']['outcome'] ?? '') === 'success'
);
$successRate = $totalSignals > 0 ? (count($successfulSignals) / $totalSignals) * 100 : 0;

echo "Total Signals: {$totalSignals}\n";
echo "Success Rate: " . number_format($successRate, 1) . "%\n";

// Analyze by signal type
$performanceByType = [];
foreach ($signalHistory['data'] as $signal) {
 $type = $signal['signal_type'];
 $outcome = $signal['performance']['outcome'] ?? 'pending';
 
 if (!isset($performanceByType[$type])) {
 $performanceByType[$type] = ['total' => 0, 'success' => 0];
 }
 
 $performanceByType[$type]['total']++;
 if ($outcome === 'success') {
 $performanceByType[$type]['success']++;
 }
}

echo "\nPerformance by Signal Type:\n";
foreach ($performanceByType as $type => $stats) {
 $rate = $stats['total'] > 0 ? ($stats['success'] / $stats['total']) * 100 : 0;
 printf("%-4s: %.1f%% (%d/%d)\n", 
 strtoupper($type), 
 $rate, 
 $stats['success'], 
 $stats['total']
 );
}

// 4. Signal strength distribution
echo "\n Signal Strength Distribution:\n";
$confidenceRanges = [
 'Very High (90-100%)' => 0,
 'High (80-89%)' => 0,
 'Medium (70-79%)' => 0,
 'Low (60-69%)' => 0,
 'Very Low (<60%)' => 0
];

foreach ($activeSignals['data'] as $signal) {
 $confidence = $signal['confidence'];
 if ($confidence >= 90) $confidenceRanges['Very High (90-100%)']++;
 elseif ($confidence >= 80) $confidenceRanges['High (80-89%)']++;
 elseif ($confidence >= 70) $confidenceRanges['Medium (70-79%)']++;
 elseif ($confidence >= 60) $confidenceRanges['Low (60-69%)']++;
 else $confidenceRanges['Very Low (<60%)']++;
}

foreach ($confidenceRanges as $range => $count) {
 if ($count > 0) {
 echo "{$range}: {$count} signals\n";
 }
}

// 5. Real-time signal monitoring setup
echo "\n Setting up signal alerts:\n";
$alertSettings = [
 'min_confidence' => 85,
 'symbols' => ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'NVDA'],
 'signal_types' => ['buy', 'sell'],
 'notifications' => true
];

echo "Monitoring " . count($alertSettings['symbols']) . " symbols\n";
echo "Minimum confidence: {$alertSettings['min_confidence']}%\n";
echo "Alert types: " . implode(', ', $alertSettings['signal_types']) . "\n";

// 6. Advanced signal filtering and analysis
$advancedSignals = $client->signals()->active([
 'signal_type' => SignalType::BUY,
 'min_confidence' => 75,
 'price_range' => ['min' => 50, 'max' => 500],
 'sectors' => ['Technology', 'Healthcare'],
 'include_fundamentals' => true
]);

echo "\n Advanced Signal Analysis (Tech/Healthcare Buy Signals):\n";
foreach ($advancedSignals['data'] as $signal) {
 if (isset($signal['fundamentals'])) {
 $pe = $signal['fundamentals']['pe_ratio'] ?? 'N/A';
 $revenue_growth = $signal['fundamentals']['revenue_growth'] ?? 'N/A';
 
 printf("%-6s (PE: %-6s, Growth: %-6s) Conf: %d%%\n",
 $signal['symbol'],
 $pe,
 $revenue_growth,
 $signal['confidence']
 );
 }
}

Response Structure Examples:

// signals()->active() response:
{
 "data": [
 {
 "id": "signal_12345",
 "symbol": "AAPL",
 "signal_type": "buy",
 "confidence": 85,
 "current_price": 175.43,
 "target_price": 190.00,
 "stop_loss": 165.00,
 "reasoning": "Strong earnings growth and technical breakout",
 "generated_at": "2025-10-22T14:30:00Z",
 "expires_at": "2025-10-23T14:30:00Z",
 "fundamentals": {
 "pe_ratio": 28.5,
 "revenue_growth": 12.3,
 "profit_margin": 23.8
 }
 }
 ],
 "metadata": {
 "count": 15,
 "filter_applied": "min_confidence: 70",
 "generated_at": "2025-10-22T16:00:00Z"
 }
}

// signals()->history() response:
{
 "data": [
 {
 "signal_id": "signal_12345",
 "symbol": "AAPL",
 "signal_type": "buy",
 "confidence": 85,
 "entry_price": 175.43,
 "exit_price": 182.15,
 "performance": {
 "outcome": "success",
 "return_percent": 3.83,
 "holding_period_days": 5
 }
 }
 ],
 "metadata": {
 "total_signals": 45,
 "success_rate": 67.8,
 "period_days": 30
 }
}

Real-time Streaming

// 1. WebSocket token management with caching
$tokenResponse = $client->streaming()->getToken();

if ($tokenResponse->successful()) {
 $tokenData = $tokenResponse->data();
 $wsToken = $tokenData['token'];
 $wsUrl = $tokenData['websocket_url'];
 $expiresAt = $tokenData['expires_at'];
 
 echo "WebSocket Authentication:\n";
 echo "Token: " . substr($wsToken, 0, 20) . "...\n";
 echo "URL: {$wsUrl}\n";
 echo "Expires: {$expiresAt}\n\n";
 
 // 2. Token validation and refresh management
 if ($client->streaming()->validateToken($wsToken)) {
 echo "Token is valid\n";
 } else {
 echo "Token expired, refreshing...\n";
 $refreshResponse = $client->streaming()->refreshToken();
 if ($refreshResponse->successful()) {
 $wsToken = $refreshResponse->data('token');
 echo "Token refreshed successfully\n";
 }
 }
}

// 3. WebSocket connection implementation (JavaScript client-side)
echo "\n WebSocket Client Implementation:\n";
echo "```javascript\n";
echo "class WioexStreamingClient {\n";
echo "constructor(token, url) {\n";
echo "this.token = token;\n";
echo "this.url = url;\n";
echo "this.ws = null;\n";
echo "this.subscriptions = new Set();\n";
echo "this.reconnectAttempts = 0;\n";
echo "this.maxReconnectAttempts = 5;\n";
echo "this.heartbeatInterval = null;\n";
echo "}\n\n";

echo "connect() {\n";
echo "this.ws = new WebSocket(`\${this.url}?token=\${this.token}`);\n\n";

echo "this.ws.onopen = () => {\n";
echo "console.log(' Connected to WioEX streaming');\n";
echo "this.reconnectAttempts = 0;\n";
echo "this.startHeartbeat();\n";
echo "this.resubscribeAll();\n";
echo "};\n\n";

echo "this.ws.onmessage = (event) => {\n";
echo "const data = JSON.parse(event.data);\n";
echo "this.handleMessage(data);\n";
echo "};\n\n";

echo "this.ws.onclose = (event) => {\n";
echo "console.log(' Connection closed:', event.code);\n";
echo "this.stopHeartbeat();\n";
echo "this.handleReconnect();\n";
echo "};\n\n";

echo "this.ws.onerror = (error) => {\n";
echo "console.error(' WebSocket error:', error);\n";
echo "};\n";
echo "}\n\n";

echo "// Subscribe to real-time stock quotes\n";
echo "subscribeToQuotes(symbols) {\n";
echo "const message = {\n";
echo "action: 'subscribe',\n";
echo "channel: 'stocks.quotes',\n";
echo "symbols: symbols\n";
echo "};\n";
echo "this.send(message);\n";
echo "symbols.forEach(symbol => this.subscriptions.add(`quotes:\${symbol}`));\n";
echo "}\n\n";

echo "// Subscribe to trading signals\n";
echo "subscribeToSignals(options = {}) {\n";
echo "const message = {\n";
echo "action: 'subscribe',\n";
echo "channel: 'signals',\n";
echo "filter: {\n";
echo "min_confidence: options.minConfidence || 70,\n";
echo "symbols: options.symbols || [],\n";
echo "signal_types: options.signalTypes || ['buy', 'sell']\n";
echo "}\n";
echo "};\n";
echo "this.send(message);\n";
echo "this.subscriptions.add('signals');\n";
echo "}\n\n";

echo "// Handle incoming messages\n";
echo "handleMessage(data) {\n";
echo "switch(data.type) {\n";
echo "case 'quote_update':\n";
echo "this.onQuoteUpdate(data.payload);\n";
echo "break;\n";
echo "case 'signal_alert':\n";
echo "this.onSignalAlert(data.payload);\n";
echo "break;\n";
echo "case 'market_status':\n";
echo "this.onMarketStatus(data.payload);\n";
echo "break;\n";
echo "case 'heartbeat':\n";
echo "this.onHeartbeat(data.payload);\n";
echo "break;\n";
echo "}\n";
echo "}\n\n";

echo "// Real-time quote updates\n";
echo "onQuoteUpdate(quote) {\n";
echo "console.log(` \${quote.symbol}: $\${quote.price} (\${quote.change > 0 ? '+' : ''}\${quote.change}%)`);\n";
echo "\n";
echo "// Update portfolio display\n";
echo "this.updatePortfolioDisplay(quote);\n";
echo "\n";
echo "// Check for significant moves\n";
echo "if (Math.abs(quote.change_percent) > 5) {\n";
echo "this.alertSignificantMove(quote);\n";
echo "}\n";
echo "}\n\n";

echo "// Trading signal alerts\n";
echo "onSignalAlert(signal) {\n";
echo "const emoji = signal.signal_type === 'buy' ? '' : '';\n";
echo "console.log(`\${emoji} Signal: \${signal.symbol} \${signal.signal_type.toUpperCase()} (Confidence: \${signal.confidence}%)`);\n";
echo "\n";
echo "// Show desktop notification\n";
echo "if (Notification.permission === 'granted') {\n";
echo "new Notification(`Trading Signal: \${signal.symbol}`, {\n";
echo "body: `\${signal.signal_type.toUpperCase()} signal with \${signal.confidence}% confidence`,\n";
echo "icon: '/assets/wioex-icon.png'\n";
echo "});\n";
echo "}\n";
echo "}\n\n";

echo "// Market status updates\n";
echo "onMarketStatus(status) {\n";
echo "console.log(` Market Status: \${status.nyse.status}`);\n";
echo "this.updateMarketStatusDisplay(status);\n";
echo "}\n";
echo "}\n\n";

echo "// Initialize streaming client\n";
echo "const streamingClient = new WioexStreamingClient('{$wsToken}', '{$wsUrl}');\n";
echo "streamingClient.connect();\n\n";

echo "// Subscribe to portfolio updates\n";
echo "streamingClient.subscribeToQuotes(['AAPL', 'GOOGL', 'MSFT', 'TSLA']);\n\n";

echo "// Subscribe to high-confidence signals\n";
echo "streamingClient.subscribeToSignals({\n";
echo "minConfidence: 80,\n";
echo "symbols: ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'NVDA'],\n";
echo "signalTypes: ['buy', 'sell']\n";
echo "});\n";
echo "```\n\n";

// 4. PHP-based streaming with ReactPHP (server-side)
echo "PHP Server-Side Streaming (ReactPHP):\n";
echo "```php\n";
echo "use React\\Socket\\Connector;\n";
echo "use Ratchet\\Client\\WebSocket;\n";
echo "use Ratchet\\Client\\Connector as WsConnector;\n\n";

echo "// Async streaming handler\n";
echo "class WioexStreamHandler {\n";
echo "private \$client;\n";
echo "private \$subscribers = [];\n";
echo "private \$lastPrices = [];\n\n";

echo "public function __construct(WioexClient \$client) {\n";
echo "\$this->client = \$client;\n";
echo "}\n\n";

echo "public function startStreaming() {\n";
echo "\$tokenResponse = \$this->client->streaming()->getToken();\n";
echo "\$wsUrl = \$tokenResponse->data('websocket_url');\n";
echo "\$token = \$tokenResponse->data('token');\n\n";

echo "\$connector = new WsConnector();\n";
echo "\$connector(\$wsUrl . '?token=' . \$token)\n";
echo "->then(function (WebSocket \$conn) {\n";
echo "echo \" Connected to WioEX streaming\\n\";\n\n";

echo "// Subscribe to portfolio symbols\n";
echo "\$conn->send(json_encode([\n";
echo "'action' => 'subscribe',\n";
echo "'channel' => 'stocks.quotes',\n";
echo "'symbols' => ['AAPL', 'GOOGL', 'MSFT', 'TSLA']\n";
echo "]));\n\n";

echo "\$conn->on('message', function (\$msg) {\n";
echo "\$data = json_decode(\$msg->getPayload(), true);\n";
echo "\$this->handleStreamingData(\$data);\n";
echo "});\n\n";

echo "\$conn->on('close', function (\$code = null, \$reason = null) {\n";
echo "echo \"Connection closed ({\$code} - {\$reason})\\n\";\n";
echo "});\n\n";

echo "}, function (\\Exception \$e) {\n";
echo "echo \"Could not connect: {\$e->getMessage()}\\n\";\n";
echo "});\n";
echo "}\n\n";

echo "private function handleStreamingData(array \$data) {\n";
echo "switch (\$data['type']) {\n";
echo "case 'quote_update':\n";
echo "\$this->processQuoteUpdate(\$data['payload']);\n";
echo "break;\n";
echo "case 'signal_alert':\n";
echo "\$this->processSignalAlert(\$data['payload']);\n";
echo "break;\n";
echo "}\n";
echo "}\n\n";

echo "private function processQuoteUpdate(array \$quote) {\n";
echo "\$symbol = \$quote['symbol'];\n";
echo "\$price = \$quote['price'];\n";
echo "\$change = \$quote['change_percent'];\n\n";

echo "// Calculate price movement significance\n";
echo "\$lastPrice = \$this->lastPrices[\$symbol] ?? \$price;\n";
echo "\$priceMovement = ((\$price - \$lastPrice) / \$lastPrice) * 100;\n\n";

echo "echo \" {\$symbol}: ${\$price} ({\$change}%) Movement: {\$priceMovement}%\\n\";\n\n";

echo "// Store for next comparison\n";
echo "\$this->lastPrices[\$symbol] = \$price;\n\n";

echo "// Alert on significant moves\n";
echo "if (abs(\$priceMovement) > 2) {\n";
echo "\$this->sendAlert(\$symbol, \$price, \$priceMovement);\n";
echo "}\n";
echo "}\n\n";

echo "private function sendAlert(string \$symbol, float \$price, float \$movement) {\n";
echo "\$message = \" {\$symbol} significant move: ${\$price} ({\$movement}%)\";\n";
echo "echo \$message . \"\\n\";\n";
echo "\n";
echo "// Send to notification service, database, etc.\n";
echo "// \$this->notificationService->send(\$message);\n";
echo "}\n";
echo "}\n";
echo "```\n\n";

// 5. Streaming connection management
echo "Connection Management Best Practices:\n";
echo "```php\n";
echo "// Token refresh strategy\n";
echo "\$tokenManager = new class(\$client) {\n";
echo "private \$client;\n";
echo "private \$currentToken;\n";
echo "private \$tokenExpiry;\n\n";

echo "public function __construct(\$client) {\n";
echo "\$this->client = \$client;\n";
echo "\$this->refreshToken();\n";
echo "}\n\n";

echo "public function getValidToken(): string {\n";
echo "if (\$this->isTokenExpiring()) {\n";
echo "\$this->refreshToken();\n";
echo "}\n";
echo "return \$this->currentToken;\n";
echo "}\n\n";

echo "private function isTokenExpiring(): bool {\n";
echo "return time() > (\$this->tokenExpiry - 300); // Refresh 5 minutes early\n";
echo "}\n\n";

echo "private function refreshToken(): void {\n";
echo "\$response = \$this->client->streaming()->getToken();\n";
echo "\$this->currentToken = \$response->data('token');\n";
echo "\$this->tokenExpiry = strtotime(\$response->data('expires_at'));\n";
echo "}\n";
echo "};\n";
echo "```\n";

WebSocket Message Examples:

// Subscription message:
{
 "action": "subscribe",
 "channel": "stocks.quotes",
 "symbols": ["AAPL", "GOOGL", "MSFT"]
}

// Quote update message:
{
 "type": "quote_update",
 "timestamp": "2025-10-22T16:15:30Z",
 "payload": {
 "symbol": "AAPL",
 "price": 175.43,
 "change": 2.15,
 "change_percent": 1.24,
 "volume": 62547890,
 "bid": 175.40,
 "ask": 175.45,
 "last_trade_time": "2025-10-22T16:15:29Z"
 }
}

// Signal alert message:
{
 "type": "signal_alert",
 "timestamp": "2025-10-22T16:15:30Z",
 "payload": {
 "signal_id": "signal_67890",
 "symbol": "TSLA",
 "signal_type": "buy",
 "confidence": 87,
 "current_price": 245.67,
 "target_price": 265.00,
 "reasoning": "Technical breakout with volume confirmation"
 }
}

Market Status

// Works with or without API key
$status = $client->markets()->status();

$nyse = $status['markets']['nyse'];
echo "NYSE Status: " . $nyse['status'] . "\n";
echo "Market Time: " . $nyse['market_time'] . "\n";
echo "Trading Hours: " . $nyse['hours']['regular']['open'] . 
 " - " . $nyse['hours']['regular']['close'] . "\n";

News & Analysis

// 1. Comprehensive news analysis for portfolio symbols
$portfolioSymbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA'];
$newsAnalysis = [];

foreach ($portfolioSymbols as $symbol) {
 $latestNews = $client->news()->latest($symbol, [
 'limit' => 10,
 'sentiment_analysis' => true,
 'include_summary' => true
 ]);
 
 echo "Latest News for {$symbol}:\n";
 $sentimentScore = 0;
 $totalArticles = count($latestNews['articles']);
 
 foreach ($latestNews['articles'] as $article) {
 $publishedTime = new DateTime($article['published_at']);
 $hoursAgo = $publishedTime->diff(new DateTime())->h;
 
 // Sentiment indicators
 $sentiment = $article['sentiment']['label'] ?? 'neutral';
 $sentimentEmoji = match($sentiment) {
 'positive' => '',
 'negative' => '',
 'neutral' => '',
 default => ''
 };
 
 printf("%s [%dh ago] %s\n", 
 $sentimentEmoji, 
 $hoursAgo, 
 substr($article['title'], 0, 80) . '...'
 );
 
 // Accumulate sentiment scores
 $sentimentScore += $article['sentiment']['score'] ?? 0;
 
 // Show article summary if available
 if (isset($article['summary'])) {
 echo "Summary: " . substr($article['summary'], 0, 100) . "...\n";
 }
 }
 
 // Calculate overall sentiment
 $avgSentiment = $totalArticles > 0 ? $sentimentScore / $totalArticles : 0;
 $overallMood = $avgSentiment > 0.1 ? 'Positive' : ($avgSentiment < -0.1 ? 'Negative' : 'Neutral');
 
 echo "Overall Sentiment: {$overallMood} (Score: " . number_format($avgSentiment, 2) . ")\n";
 echo "Articles analyzed: {$totalArticles}\n\n";
 
 $newsAnalysis[$symbol] = [
 'sentiment_score' => $avgSentiment,
 'article_count' => $totalArticles,
 'overall_mood' => $overallMood
 ];
}

// 2. Company-specific analysis with financial correlation
foreach ($portfolioSymbols as $symbol) {
 $companyAnalysis = $client->news()->companyAnalysis($symbol, [
 'include_financials' => true,
 'analysis_period' => 30 // Last 30 days
 ]);
 
 echo "{$symbol} Company Analysis:\n";
 
 // Key metrics
 if (isset($companyAnalysis['metrics'])) {
 $metrics = $companyAnalysis['metrics'];
 echo "News Coverage: {$metrics['total_articles']} articles\n";
 echo "Media Sentiment: {$metrics['sentiment']['overall']} ";
 echo "({$metrics['sentiment']['positive']}% positive, ";
 echo "{$metrics['sentiment']['negative']}% negative)\n";
 
 // Trending topics
 if (isset($metrics['trending_topics'])) {
 echo "Trending Topics: " . implode(', ', array_slice($metrics['trending_topics'], 0, 5)) . "\n";
 }
 }
 
 // Recent developments
 if (isset($companyAnalysis['recent_developments'])) {
 echo "Recent Developments:\n";
 foreach (array_slice($companyAnalysis['recent_developments'], 0, 3) as $development) {
 printf("β€’ %s (%s)\n", 
 $development['headline'], 
 $development['category']
 );
 }
 }
 echo "\n";
}

// 3. Market news aggregation and categorization
$marketNews = $client->news()->marketNews([
 'categories' => ['earnings', 'mergers', 'ipo', 'regulations'],
 'limit' => 20,
 'sentiment_filter' => 'all'
]);

echo "Market News Categories:\n";
$newsByCategory = [];

foreach ($marketNews['articles'] as $article) {
 $category = $article['category'];
 if (!isset($newsByCategory[$category])) {
 $newsByCategory[$category] = [];
 }
 $newsByCategory[$category][] = $article;
}

foreach ($newsByCategory as $category => $articles) {
 echo "\n " . strtoupper($category) . " ({" . count($articles) . " articles}):\n";
 
 foreach (array_slice($articles, 0, 3) as $article) {
 $impact = $article['market_impact'] ?? 'neutral';
 $impactEmoji = match($impact) {
 'high' => '',
 'medium' => '',
 'low' => '',
 default => ''
 };
 
 printf("%s %s\n", $impactEmoji, $article['title']);
 
 // Show affected symbols if available
 if (isset($article['related_symbols']) && !empty($article['related_symbols'])) {
 echo "Affects: " . implode(', ', array_slice($article['related_symbols'], 0, 5)) . "\n";
 }
 }
}

// 4. Sentiment-based trading insights
echo "\n News-Based Trading Insights:\n";

$sentimentSummary = [
 'strong_positive' => [],
 'positive' => [],
 'neutral' => [],
 'negative' => [],
 'strong_negative' => []
];

foreach ($newsAnalysis as $symbol => $analysis) {
 $score = $analysis['sentiment_score'];
 
 if ($score >= 0.3) {
 $sentimentSummary['strong_positive'][] = $symbol;
 } elseif ($score >= 0.1) {
 $sentimentSummary['positive'][] = $symbol;
 } elseif ($score <= -0.3) {
 $sentimentSummary['strong_negative'][] = $symbol;
 } elseif ($score <= -0.1) {
 $sentimentSummary['negative'][] = $symbol;
 } else {
 $sentimentSummary['neutral'][] = $symbol;
 }
}

foreach ($sentimentSummary as $sentiment => $symbols) {
 if (!empty($symbols)) {
 $emoji = match($sentiment) {
 'strong_positive' => '',
 'positive' => '',
 'neutral' => '',
 'negative' => '',
 'strong_negative' => '',
 default => ''
 };
 
 echo "{$emoji} " . str_replace('_', ' ', strtoupper($sentiment)) . ": " . implode(', ', $symbols) . "\n";
 }
}

// 5. News alert system configuration
echo "\n News Alert Configuration:\n";
$alertConfig = [
 'keywords' => ['earnings', 'merger', 'acquisition', 'FDA approval', 'partnership'],
 'symbols' => $portfolioSymbols,
 'sentiment_threshold' => 0.2, // Alert on significant sentiment changes
 'impact_level' => 'medium', // Minimum impact level
 'real_time' => true
];

echo "Monitoring keywords: " . implode(', ', $alertConfig['keywords']) . "\n";
echo "Tracking symbols: " . implode(', ', $alertConfig['symbols']) . "\n";
echo "Sentiment threshold: Β±" . $alertConfig['sentiment_threshold'] . "\n";
echo "Minimum impact: " . $alertConfig['impact_level'] . "\n";

// 6. Advanced news analysis with correlation
$advancedAnalysis = $client->news()->advancedAnalysis([
 'symbols' => $portfolioSymbols,
 'correlation_analysis' => true,
 'price_impact_analysis' => true,
 'time_decay_factor' => 0.8 // Recent news weighted more heavily
]);

echo "\n Advanced Correlation Analysis:\n";
if (isset($advancedAnalysis['correlations'])) {
 foreach ($advancedAnalysis['correlations'] as $correlation) {
 printf("News sentiment vs price: %s (RΒ² = %.3f)\n",
 $correlation['symbol'],
 $correlation['r_squared']
 );
 }
}

// News volume trends
if (isset($advancedAnalysis['volume_trends'])) {
 echo "\nNews Volume Trends:\n";
 foreach ($advancedAnalysis['volume_trends'] as $symbol => $trend) {
 $direction = $trend['change_percent'] > 0 ? '' : '';
 printf("%s %s: %+.1f%% news volume change\n",
 $direction,
 $symbol,
 $trend['change_percent']
 );
 }
}

Response Structure Examples:

// news()->latest() response:
{
 "articles": [
 {
 "id": "news_12345",
 "title": "Apple Reports Record Q4 Earnings",
 "summary": "Apple exceeded analyst expectations with strong iPhone sales...",
 "content": "Full article content...",
 "source": "Reuters",
 "author": "John Smith",
 "published_at": "2025-10-22T14:30:00Z",
 "url": "https://reuters.com/article/...",
 "sentiment": {
 "label": "positive",
 "score": 0.75,
 "confidence": 0.92
 },
 "category": "earnings",
 "market_impact": "high",
 "related_symbols": ["AAPL", "NASDAQ"]
 }
 ],
 "metadata": {
 "symbol": "AAPL",
 "total_articles": 10,
 "sentiment_distribution": {
 "positive": 60,
 "neutral": 30,
 "negative": 10
 }
 }
}

// news()->companyAnalysis() response:
{
 "symbol": "AAPL",
 "analysis_period": 30,
 "metrics": {
 "total_articles": 145,
 "sentiment": {
 "overall": "positive",
 "positive": 65,
 "neutral": 25,
 "negative": 10
 },
 "trending_topics": ["earnings", "iPhone", "AI", "services"],
 "media_coverage_trend": "increasing"
 },
 "recent_developments": [
 {
 "headline": "Apple Announces New AI Features",
 "category": "product",
 "impact": "medium",
 "date": "2025-10-20"
 }
 ]
}

Trump Effect - Social Media Market Impact

Monitor Trump's social media posts and their impact on financial markets.

// 1. Get latest posts with default settings (20 per page)
$trumpPosts = $client->news()->trumpEffect();

if ($trumpPosts->successful()) {
    $data = $trumpPosts['data'];

    // Overall market mood (0 = bearish, 1 = bullish)
    echo "Market Mood Index: {$data['mood_index']}\n";
    echo "Sentiment: " . ($data['mood_index'] > 0.6 ? 'Bullish' : ($data['mood_index'] < 0.4 ? 'Bearish' : 'Neutral')) . "\n\n";

    // Display posts
    foreach ($data['posts'] as $post) {
        echo "Time: {$post['time']} | Sentiment: {$post['sentiment']['name']}\n";
        echo "Summary: {$post['summary']}\n";

        // Show full post content (original tweet/post text)
        if (!empty($post['content'])) {
            echo "Full Content: {$post['content']}\n";
        }

        // Show affected securities
        if (!empty($post['affected_securities'])) {
            $tickers = array_column($post['affected_securities'], 'ticker');
            echo "Affected Tickers: " . implode(', ', $tickers) . "\n";
        }

        // Show sectors
        if (!empty($post['sectors'])) {
            echo "Sectors: " . implode(', ', $post['sectors']) . "\n";
        }
        echo "\n";
    }

    // Pagination
    if ($data['pagination']['has_more']) {
        echo "More posts available (use 'page' parameter)\n";
    }
}

// 2. Filter by sentiment (only bullish/positive posts)
$bullishPosts = $client->news()->trumpEffect([
    'sentiment' => ['trumpy'],
    'pageSize' => 10
]);

if ($bullishPosts->successful()) {
    echo "Bullish Posts:\n";
    foreach ($bullishPosts['data']['posts'] as $post) {
        echo "β€’ {$post['summary']}\n";
    }
}

// 3. Track specific stocks mentioned in posts
$allPosts = $client->news()->trumpEffect(['pageSize' => 100]);

if ($allPosts->successful()) {
    $trackingSymbols = ['TSLA', 'AAPL', 'BA'];
    $mentionedPosts = [];

    foreach ($allPosts['data']['posts'] as $post) {
        if (empty($post['affected_securities'])) continue;

        $tickers = array_column($post['affected_securities'], 'ticker');
        $mentioned = array_intersect($trackingSymbols, $tickers);

        if (!empty($mentioned)) {
            foreach ($mentioned as $ticker) {
                if (!isset($mentionedPosts[$ticker])) {
                    $mentionedPosts[$ticker] = [];
                }
                $mentionedPosts[$ticker][] = $post;
            }
        }
    }

    // Display mentions
    foreach ($trackingSymbols as $ticker) {
        if (isset($mentionedPosts[$ticker])) {
            $count = count($mentionedPosts[$ticker]);
            echo "{$ticker}: {$count} mentions\n";

            // Show latest mention
            $latestPost = $mentionedPosts[$ticker][0];
            echo "Latest: {$latestPost['summary']}\n";
            echo "Sentiment: {$latestPost['sentiment']['name']}\n\n";
        } else {
            echo "{$ticker}: No mentions\n";
        }
    }
}

// 4. Analyze sentiment distribution
$response = $client->news()->trumpEffect(['pageSize' => 50]);

if ($response->successful()) {
    $sentiments = ['trumpy' => 0, 'neutral' => 0, 'grumpy' => 0];

    foreach ($response['data']['posts'] as $post) {
        $sentiment = $post['sentiment']['name'];
        if (isset($sentiments[$sentiment])) {
            $sentiments[$sentiment]++;
        }
    }

    $total = array_sum($sentiments);
    echo "Sentiment Distribution (Last 50 Posts):\n";
    echo "Trumpy (Bullish): " . round(($sentiments['trumpy'] / $total) * 100, 1) . "%\n";
    echo "Neutral: " . round(($sentiments['neutral'] / $total) * 100, 1) . "%\n";
    echo "Grumpy (Bearish): " . round(($sentiments['grumpy'] / $total) * 100, 1) . "%\n";
}

// 5. Monitor specific sectors
$response = $client->news()->trumpEffect(['pageSize' => 100]);

if ($response->successful()) {
    $sectorImpact = [];

    foreach ($response['data']['posts'] as $post) {
        if (empty($post['sectors'])) continue;

        foreach ($post['sectors'] as $sector) {
            if (!isset($sectorImpact[$sector])) {
                $sectorImpact[$sector] = [
                    'count' => 0,
                    'sentiments' => ['trumpy' => 0, 'neutral' => 0, 'grumpy' => 0]
                ];
            }

            $sectorImpact[$sector]['count']++;
            $sentiment = $post['sentiment']['name'];
            if (isset($sectorImpact[$sector]['sentiments'][$sentiment])) {
                $sectorImpact[$sector]['sentiments'][$sentiment]++;
            }
        }
    }

    // Display sector analysis
    echo "Sector Impact Analysis:\n";
    foreach ($sectorImpact as $sector => $data) {
        $positive = $data['sentiments']['trumpy'];
        $negative = $data['sentiments']['grumpy'];
        $netSentiment = $positive - $negative;

        echo "{$sector}: {$data['count']} mentions (Net Sentiment: " .
             ($netSentiment > 0 ? "+{$netSentiment}" : $netSentiment) . ")\n";
    }
}

// 6. Pagination through all posts
$page = 1;
$allTrumpPosts = [];

while ($page <= 5) {  // Get first 5 pages
    $response = $client->news()->trumpEffect([
        'page' => $page,
        'pageSize' => 20
    ]);

    if ($response->successful()) {
        $data = $response['data'];
        $allTrumpPosts = array_merge($allTrumpPosts, $data['posts']);

        if (!$data['pagination']['has_more']) {
            break;  // No more posts
        }

        $page++;
    } else {
        break;  // Error occurred
    }
}

echo "Total Trump posts retrieved: " . count($allTrumpPosts) . "\n";

Currency Exchange

// Exchange rates
$rates = $client->currency()->baseUsd();
$eurRates = $client->currency()->allRates('EUR');

// Currency conversion
$conversion = $client->currency()->calculator('USD', 'EUR', 100);
echo "100 USD = " . $conversion['converted_amount'] . " EUR\n";

// Historical exchange rates
$history = $client->currency()->graph('USD', 'EUR', '1d');

Account Management

// Account balance
$balance = $client->account()->balance();
echo "Credits: " . $balance['credits'] . "\n";

// Usage statistics
$usage = $client->account()->usage(30); // Last 30 days
echo "API Calls: " . $usage['total_requests'] . "\n";

// Analytics
$analytics = $client->account()->analytics('month');

Advanced Features

Bulk Operations & Portfolio Management

// 1. Portfolio batch processing with intelligent rate limiting
$portfolioSymbols = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA', 'META', 'NVDA', 'AMD'];

echo "Processing Portfolio (" . count($portfolioSymbols) . " symbols):\n\n";

// Bulk quotes with automatic batching
$portfolioQuotes = $client->stocks()->quoteBulk($portfolioSymbols, [
 'batch_size' => 3, // Process 3 symbols at a time
 'delay_between_batches' => 150, // 150ms delay between batches
 'continue_on_error' => true, // Don't stop if one symbol fails
 'include_signals' => true // Include trading signals
]);

// Process portfolio results
$totalValue = 0;
$gainers = $losers = 0;
$portfolioSummary = [];

foreach ($portfolioQuotes['data'] as $symbol => $quote) {
 if (isset($quote['error'])) {
 echo "{$symbol}: {$quote['error']}\n";
 continue;
 }
 
 $price = $quote['market']['price'];
 $change = $quote['market']['change']['percent'];
 $volume = $quote['market']['volume'];
 
 // Assume 100 shares for calculation
 $position_value = $price * 100;
 $totalValue += $position_value;
 
 if ($change > 0) $gainers++;
 else if ($change < 0) $losers++;
 
 printf("%-6s $%-8.2f %+.2f%% Vol: %-12s Value: $%-10.2f\n",
 $symbol,
 $price,
 $change,
 number_format($volume),
 $position_value
 );
 
 // Check for trading signals
 if (isset($quote['signal']) && $quote['signal']['confidence'] > 75) {
 $signalEmoji = $quote['signal']['signal_type'] === 'buy' ? '' : '';
 echo "{$signalEmoji} Signal: {$quote['signal']['signal_type']} (confidence: {$quote['signal']['confidence']}%)\n";
 }
 
 $portfolioSummary[$symbol] = [
 'price' => $price,
 'change' => $change,
 'position_value' => $position_value,
 'signal' => $quote['signal'] ?? null
 ];
}

echo "\n Portfolio Summary:\n";
echo "Total Value: $" . number_format($totalValue, 2) . "\n";
echo "Gainers: {$gainers} | Losers: {$losers} | Neutral: " . (count($portfolioSymbols) - $gainers - $losers) . "\n";
echo "Processing Time: {$portfolioQuotes['metadata']['processing_time']}ms\n\n";

// 2. Historical data bulk analysis
echo "Historical Analysis (Last 30 days):\n";

$historicalBulk = $client->stocks()->timelineBulk(
 array_slice($portfolioSymbols, 0, 4), // Analyze top 4 positions
 [
 'period' => '30d',
 'interval' => '1d',
 'batch_size' => 2,
 'include_volume_analysis' => true
 ]
);

foreach ($historicalBulk['data'] as $symbol => $timeline) {
 if (empty($timeline)) continue;
 
 $prices = array_column($timeline, 'close');
 $volumes = array_column($timeline, 'volume');
 
 // Calculate statistics
 $currentPrice = end($prices);
 $startPrice = reset($prices);
 $monthlyReturn = (($currentPrice - $startPrice) / $startPrice) * 100;
 
 $avgVolume = array_sum($volumes) / count($volumes);
 $volatility = $this->calculateVolatility($prices);
 
 printf("%-6s: %+.2f%% return, %.2f%% volatility, avg vol: %s\n",
 $symbol,
 $monthlyReturn,
 $volatility,
 number_format($avgVolume)
 );
}

// 3. Bulk signal analysis for decision making
echo "\n Portfolio Signal Analysis:\n";

$signalsBulk = $client->signals()->activeBulk($portfolioSymbols, [
 'min_confidence' => 70,
 'batch_size' => 4,
 'include_fundamentals' => true
]);

$signalStrength = ['strong_buy' => [], 'buy' => [], 'hold' => [], 'sell' => [], 'strong_sell' => []];

foreach ($signalsBulk['data'] as $symbol => $signals) {
 if (empty($signals)) continue;
 
 $primarySignal = $signals[0]; // Highest confidence signal
 $confidence = $primarySignal['confidence'];
 $type = $primarySignal['signal_type'];
 
 // Categorize by strength
 if ($type === 'buy' && $confidence >= 85) {
 $signalStrength['strong_buy'][] = $symbol;
 } elseif ($type === 'buy') {
 $signalStrength['buy'][] = $symbol;
 } elseif ($type === 'sell' && $confidence >= 85) {
 $signalStrength['strong_sell'][] = $symbol;
 } elseif ($type === 'sell') {
 $signalStrength['sell'][] = $symbol;
 } else {
 $signalStrength['hold'][] = $symbol;
 }
}

foreach ($signalStrength as $strength => $symbols) {
 if (!empty($symbols)) {
 $emoji = match($strength) {
 'strong_buy' => '',
 'buy' => '',
 'hold' => '',
 'sell' => '',
 'strong_sell' => '',
 default => ''
 };
 echo "{$emoji} " . strtoupper(str_replace('_', ' ', $strength)) . ": " . implode(', ', $symbols) . "\n";
 }
}

// 4. Risk analysis and position sizing
echo "\n Risk Analysis:\n";

class PortfolioRiskAnalyzer
{
 public function analyzePortfolio(array $portfolioData): array
 {
 $totalValue = array_sum(array_column($portfolioData, 'position_value'));
 $riskMetrics = [];
 
 foreach ($portfolioData as $symbol => $position) {
 $weight = $position['position_value'] / $totalValue;
 $volatilityRisk = $this->calculateRisk($position['change']);
 
 $riskMetrics[$symbol] = [
 'weight' => $weight * 100,
 'risk_level' => $volatilityRisk,
 'contribution_to_risk' => $weight * abs($position['change'])
 ];
 }
 
 return $riskMetrics;
 }
 
 private function calculateRisk(float $change): string
 {
 $absChange = abs($change);
 if ($absChange > 5) return 'High';
 if ($absChange > 2) return 'Medium';
 return 'Low';
 }
}

$riskAnalyzer = new PortfolioRiskAnalyzer();
$riskMetrics = $riskAnalyzer->analyzePortfolio($portfolioSummary);

echo "Position Risk Breakdown:\n";
foreach ($riskMetrics as $symbol => $risk) {
 printf("%-6s: %.1f%% weight, %s risk, %.2f%% risk contribution\n",
 $symbol,
 $risk['weight'],
 $risk['risk_level'],
 $risk['contribution_to_risk']
 );
}

// 5. Automated rebalancing suggestions
echo "\n Rebalancing Suggestions:\n";

$targetWeight = 100 / count($portfolioSummary); // Equal weight target
foreach ($riskMetrics as $symbol => $risk) {
 $currentWeight = $risk['weight'];
 $deviation = $currentWeight - $targetWeight;
 
 if (abs($deviation) > 2) { // Significant deviation
 $action = $deviation > 0 ? 'REDUCE' : 'INCREASE';
 $amount = abs($deviation);
 printf("%-6s: %s position by %.1f%% (current: %.1f%%, target: %.1f%%)\n",
 $symbol,
 $action,
 $amount,
 $currentWeight,
 $targetWeight
 );
 }
}

// 6. Bulk operations performance monitoring
echo "\n Performance Metrics:\n";
$totalProcessingTime = $portfolioQuotes['metadata']['processing_time'] + 
 ($historicalBulk['metadata']['processing_time'] ?? 0) +
 ($signalsBulk['metadata']['processing_time'] ?? 0);

echo "Total API calls: " . (count($portfolioSymbols) * 3) . "\n";
echo "Total processing time: {$totalProcessingTime}ms\n";
echo "Average per symbol: " . number_format($totalProcessingTime / count($portfolioSymbols), 1) . "ms\n";
echo "Rate limit efficiency: " . number_format((count($portfolioSymbols) / ($totalProcessingTime / 1000)) * 60, 1) . " symbols/minute\n";

// Helper function for volatility calculation
function calculateVolatility(array $prices): float
{
 if (count($prices) < 2) return 0;
 
 $returns = [];
 for ($i = 1; $i < count($prices); $i++) {
 $returns[] = ($prices[$i] - $prices[$i - 1]) / $prices[$i - 1];
 }
 
 $mean = array_sum($returns) / count($returns);
 $variance = array_sum(array_map(fn($r) => pow($r - $mean, 2), $returns)) / count($returns);
 
 return sqrt($variance) * 100 * sqrt(252); // Annualized volatility
}

Caching & Performance Optimization

use Wioex\SDK\Cache\CacheManager;
use Wioex\SDK\Enums\CacheDriver;

// 1. Enable advanced caching for better performance
$client = new WioexClient([
 'api_key' => 'your-api-key-here',
 'cache' => [
 'default' => 'file',
 'drivers' => [
 'memory' => [
 'driver' => 'memory',
 'config' => ['max_items' => 1000]
 ],
 'file' => [
 'driver' => 'file',
 'config' => [
 'cache_dir' => '/tmp/wioex_cache',
 'extension' => '.cache'
 ]
 ]
 ]
 ]
]);

// 2. Cache-aware data fetching
$cache = $client->getCache();
echo "Cache Performance Demo:\n\n";

// Tagged caching for organized cache management
$portfolioCache = $cache->tags(['portfolio', 'quotes']);
$analysisCache = $cache->tags(['analysis', 'historical']);

// Cache stocks quotes with TTL
$portfolioSymbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA'];
$cacheKey = 'portfolio_quotes_' . md5(implode(',', $portfolioSymbols));

echo "1. Fetching portfolio quotes (first call - cache miss):\n";
$startTime = microtime(true);

$quotes = $portfolioCache->remember($cacheKey, function () use ($client, $portfolioSymbols) {
 echo "Cache miss - fetching from API...\n";
 return $client->stocks()->quote(implode(',', $portfolioSymbols));
}, 300); // Cache for 5 minutes

$firstCallTime = (microtime(true) - $startTime) * 1000;
echo "Time: " . number_format($firstCallTime, 2) . "ms\n\n";

// Second call - should be from cache
echo "2. Fetching same data (second call - cache hit):\n";
$startTime = microtime(true);

$cachedQuotes = $portfolioCache->remember($cacheKey, function () use ($client, $portfolioSymbols) {
 echo "This shouldn't appear (cache should hit)\n";
 return $client->stocks()->quote(implode(',', $portfolioSymbols));
}, 300);

$secondCallTime = (microtime(true) - $startTime) * 1000;
echo "Cache hit - Time: " . number_format($secondCallTime, 2) . "ms\n";
echo "Performance improvement: " . number_format(($firstCallTime / $secondCallTime), 1) . "x faster\n\n";

// 3. Layered caching strategy for different data types
echo "3. Layered Caching Strategy:\n";

// Fast-changing data (quotes) - short TTL
$realtimeCache = $cache->tags(['realtime']);
$quickQuote = $realtimeCache->remember('AAPL_quote', function () use ($client) {
 return $client->stocks()->quote('AAPL');
}, 60); // 1 minute TTL

echo "Real-time data (1min TTL): AAPL quote cached\n";

// Medium-changing data (company info) - medium TTL 
$companyCache = $cache->tags(['company_info']);
$companyInfo = $companyCache->remember('AAPL_info', function () use ($client) {
 return $client->stocks()->info('AAPL');
}, 3600); // 1 hour TTL

echo "Company data (1hr TTL): AAPL info cached\n";

// Slow-changing data (historical) - long TTL
$historicalCache = $cache->tags(['historical']);
$historical = $historicalCache->remember('AAPL_30d_timeline', function () use ($client) {
 return $client->stocks()->timeline('AAPL', ['interval' => '1day', 'size' => 30]);
}, 86400); // 24 hours TTL

echo "Historical data (24hr TTL): AAPL timeline cached\n\n";

// 4. Smart cache invalidation
echo "4. Smart Cache Management:\n";

// Cache with dependency tracking
$dependentCache = $cache->tags(['dependent', 'portfolio']);
$portfolioAnalysis = $dependentCache->remember('portfolio_analysis_v2', function () use ($quotes) {
 echo "Computing portfolio analysis...\n";
 
 $analysis = [
 'total_value' => 0,
 'daily_change' => 0,
 'top_performer' => null,
 'analysis_time' => time()
 ];
 
 $maxChange = -999;
 foreach ($quotes['tickers'] as $ticker) {
 $analysis['total_value'] += $ticker['market']['price'] * 100;
 $analysis['daily_change'] += $ticker['market']['change']['percent'];
 
 if ($ticker['market']['change']['percent'] > $maxChange) {
 $maxChange = $ticker['market']['change']['percent'];
 $analysis['top_performer'] = $ticker['ticker'];
 }
 }
 
 return $analysis;
}, 1800); // 30 minutes

echo "Portfolio analysis computed and cached\n";
echo "Top performer: {$portfolioAnalysis['top_performer']}\n";
echo "Total value: $" . number_format($portfolioAnalysis['total_value'], 2) . "\n\n";

// 5. Cache statistics and monitoring
echo "5. Cache Performance Monitoring:\n";

$cacheStats = $cache->getStatistics();
echo "Cache Statistics:\n";
echo "Default driver: {$cacheStats['default_driver']}\n";

foreach ($cacheStats['drivers'] as $driver => $stats) {
 $hitRate = $stats['hit_rate_percentage'] ?? 0;
 $color = $hitRate > 80 ? '' : ($hitRate > 60 ? '' : '');
 echo "{$color} {$driver}: {$hitRate}% hit rate ({$stats['hits']} hits, {$stats['misses']} misses)\n";
}

// Memory usage for file cache
if (isset($cacheStats['drivers']['file'])) {
 $fileStats = $cacheStats['drivers']['file'];
 echo "Cache size: " . number_format($fileStats['size_bytes'] / 1024, 1) . " KB\n";
 echo "Files: {$fileStats['file_count']}\n";
}

echo "\n";

// 6. Selective cache warming
echo "6. Cache Warming Strategy:\n";

function warmCache($client, $cache): void 
{
 echo "Warming cache with frequently accessed data...\n";
 
 $popularSymbols = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA'];
 $warmingStart = microtime(true);
 
 foreach ($popularSymbols as $symbol) {
 // Warm quotes cache
 $cache->tags(['quotes', 'warmed'])->remember("quote_{$symbol}", function () use ($client, $symbol) {
 return $client->stocks()->quote($symbol);
 }, 300);
 
 // Warm company info cache
 $cache->tags(['info', 'warmed'])->remember("info_{$symbol}", function () use ($client, $symbol) {
 return $client->stocks()->info($symbol);
 }, 3600);
 
 echo "{$symbol} cached\n";
 }
 
 $warmingTime = (microtime(true) - $warmingStart) * 1000;
 echo "Cache warming completed in " . number_format($warmingTime, 2) . "ms\n";
}

warmCache($client, $cache);

// 7. Cache cleanup and optimization
echo "\n7. Cache Maintenance:\n";

// Clean expired entries
$cleanedCount = $cache->cleanup();
echo "Cleaned {$cleanedCount} expired entries\n";

// Selective tag-based cleanup
$cache->tags(['realtime'])->flush();
echo "Flushed real-time cache (high turnover data)\n";

// Size-based optimization
$cacheSize = $cache->size();
echo "Total cache size: " . number_format($cacheSize / 1024, 1) . " KB\n";

if ($cacheSize > 50 * 1024 * 1024) { // 50MB threshold
 echo " Cache size large, considering cleanup of old entries\n";
 $cache->prune(0.3); // Remove 30% of least recently used
 echo "Pruned cache to optimize size\n";
}

// 8. Advanced caching patterns
echo "\n8. Advanced Caching Patterns:\n";

// Circuit breaker pattern with cache fallback
class CachedApiClient
{
 private $client;
 private $cache;
 private $failures = 0;
 private $maxFailures = 3;
 
 public function __construct($client, $cache)
 {
 $this->client = $client;
 $this->cache = $cache;
 }
 
 public function getQuoteWithFallback(string $symbol): ?array
 {
 $cacheKey = "quote_fallback_{$symbol}";
 
 // If circuit is open, use cache only
 if ($this->failures >= $this->maxFailures) {
 echo "Circuit open - using cache fallback for {$symbol}\n";
 return $this->cache->get($cacheKey);
 }
 
 try {
 $quote = $this->client->stocks()->quote($symbol);
 
 // Store in cache with extended TTL for fallback
 $this->cache->put($cacheKey, $quote, 3600);
 
 // Reset failure count on success
 $this->failures = 0;
 
 echo "Fresh data retrieved for {$symbol}\n";
 return $quote;
 
 } catch (Exception $e) {
 $this->failures++;
 echo "API failed for {$symbol}, using cache fallback\n";
 
 // Return cached data as fallback
 return $this->cache->get($cacheKey);
 }
 }
}

$cachedClient = new CachedApiClient($client, $cache);
$fallbackQuote = $cachedClient->getQuoteWithFallback('AAPL');

echo "\n9. Cache Performance Summary:\n";
echo "Cache hit rate improvement: Reduced API calls by ~80%\n";
echo "Response time improvement: 5-20x faster for cached data\n";
echo "Cost optimization: Reduced API usage and costs\n";
echo "Reliability: Graceful degradation with cache fallbacks\n";

Async Operations & Promise Handling

use Wioex\SDK\Async\AsyncClient;
use Wioex\SDK\Async\Promise;
use Wioex\SDK\Enums\AsyncOperationType;

// 1. Initialize async client for concurrent operations
$asyncClient = $client->async();
echo "Async Operations Demo:\n\n";

// 2. Concurrent data fetching with Promises
echo "1. Concurrent API Calls:\n";

$portfolioSymbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'NVDA'];
$startTime = microtime(true);

// Create multiple concurrent requests
$promises = [];
foreach ($portfolioSymbols as $symbol) {
 $promises[$symbol] = $asyncClient->stocks()->quoteAsync($symbol);
}

echo "Initiated " . count($promises) . " concurrent requests\n";

// Wait for all promises to resolve
$results = [];
foreach ($promises as $symbol => $promise) {
 try {
 $result = $promise->wait(10); // 10 second timeout
 $results[$symbol] = $result;
 echo "{$symbol}: $" . number_format($result['market']['price'], 2) . "\n";
 } catch (Exception $e) {
 echo "{$symbol}: Failed - {$e->getMessage()}\n";
 }
}

$asyncTime = (microtime(true) - $startTime) * 1000;
echo "Async completion time: " . number_format($asyncTime, 2) . "ms\n\n";

// Compare with synchronous approach
echo "2. Performance Comparison (Synchronous):\n";
$syncStartTime = microtime(true);

foreach (array_slice($portfolioSymbols, 0, 3) as $symbol) {
 $syncResult = $client->stocks()->quote($symbol);
 echo "{$symbol}: $" . number_format($syncResult['tickers'][0]['market']['price'], 2) . "\n";
}

$syncTime = (microtime(true) - $syncStartTime) * 1000;
echo "Sync completion time: " . number_format($syncTime, 2) . "ms\n";
echo "Async performance gain: " . number_format($syncTime / $asyncTime, 1) . "x faster\n\n";

// 3. Advanced Promise handling with error recovery
echo "3. Advanced Promise Patterns:\n";

class AsyncPortfolioManager
{
 private $asyncClient;
 private $results = [];
 private $errors = [];
 
 public function __construct($asyncClient)
 {
 $this->asyncClient = $asyncClient;
 }
 
 public function fetchPortfolioData(array $symbols): array
 {
 $promises = [];
 
 // Create promises for different data types
 foreach ($symbols as $symbol) {
 $promises["quote_{$symbol}"] = $this->asyncClient->stocks()->quoteAsync($symbol);
 $promises["info_{$symbol}"] = $this->asyncClient->stocks()->infoAsync($symbol);
 $promises["signals_{$symbol}"] = $this->asyncClient->signals()->activeAsync(['symbol' => $symbol]);
 }
 
 echo "Processing " . count($promises) . " async operations...\n";
 
 // Process promises with timeout and error handling
 $completed = 0;
 foreach ($promises as $key => $promise) {
 try {
 $result = $promise->wait(5); // 5 second timeout per request
 $this->results[$key] = $result;
 $completed++;
 } catch (Exception $e) {
 $this->errors[$key] = $e->getMessage();
 echo " {$key}: {$e->getMessage()}\n";
 }
 }
 
 echo "Completed: {$completed}/" . count($promises) . " operations\n";
 return $this->results;
 }
 
 public function getPortfolioSummary(): array
 {
 $summary = [
 'symbols' => [],
 'total_value' => 0,
 'signals_count' => 0,
 'data_completeness' => 0
 ];
 
 foreach ($this->results as $key => $data) {
 if (strpos($key, 'quote_') === 0) {
 $symbol = str_replace('quote_', '', $key);
 $price = $data['market']['price'] ?? 0;
 $summary['symbols'][$symbol]['price'] = $price;
 $summary['total_value'] += $price * 100; // Assume 100 shares
 } elseif (strpos($key, 'info_') === 0) {
 $symbol = str_replace('info_', '', $key);
 $summary['symbols'][$symbol]['market_cap'] = $data['market_cap'] ?? 0;
 } elseif (strpos($key, 'signals_') === 0) {
 $symbol = str_replace('signals_', '', $key);
 if (!empty($data)) {
 $summary['symbols'][$symbol]['signal'] = $data[0];
 $summary['signals_count']++;
 }
 }
 }
 
 $expectedData = count($this->results) + count($this->errors);
 $summary['data_completeness'] = count($this->results) / $expectedData * 100;
 
 return $summary;
 }
}

$portfolioManager = new AsyncPortfolioManager($asyncClient);
$portfolioData = $portfolioManager->fetchPortfolioData(['AAPL', 'GOOGL', 'MSFT']);
$summary = $portfolioManager->getPortfolioSummary();

echo "Portfolio Summary:\n";
echo "Total Value: $" . number_format($summary['total_value'], 2) . "\n";
echo "Active Signals: {$summary['signals_count']}\n";
echo "Data Completeness: " . number_format($summary['data_completeness'], 1) . "%\n\n";

// 4. Event-driven async processing
echo "4. Event-Driven Processing:\n";

$asyncClient->onProgress(function ($completed, $total, $currentOperation) {
 $percentage = ($completed / $total) * 100;
 echo "Progress: " . number_format($percentage, 1) . "% ({$completed}/{$total}) - {$currentOperation}\n";
});

$asyncClient->onError(function ($operation, $error) {
 echo "Error in {$operation}: {$error}\n";
});

$asyncClient->onComplete(function ($results) {
 echo "All operations completed: " . count($results) . " results\n";
});

// 5. Batch async operations with rate limiting
echo "\n5. Rate-Limited Batch Processing:\n";

$largeBatch = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA', 'META', 'NVDA', 'AMD', 'CRM', 'NFLX'];

$batchProcessor = $asyncClient->batch()
 ->setMaxConcurrent(3) // Max 3 concurrent requests
 ->setDelayBetweenBatches(200) // 200ms delay between batches
 ->setRetryAttempts(2) // Retry failed requests twice
 ->setTimeout(10); // 10 second timeout

foreach ($largeBatch as $symbol) {
 $batchProcessor->add(
 AsyncOperationType::STOCK_QUOTE,
 ['symbol' => $symbol],
 "quote_{$symbol}"
 );
}

echo "Processing batch of " . count($largeBatch) . " symbols...\n";

$batchResults = $batchProcessor->execute();

echo "Batch completed:\n";
echo "Successful: {$batchResults['successful']}\n";
echo "Failed: {$batchResults['failed']}\n";
echo "Total time: {$batchResults['execution_time']}ms\n";
echo "Average per symbol: " . number_format($batchResults['execution_time'] / count($largeBatch), 1) . "ms\n\n";

// 6. Real-time async streaming integration
echo "6. Async Streaming Integration:\n";

$streamingAsync = $asyncClient->streaming();

// Async token management
$tokenPromise = $streamingAsync->getTokenAsync();
$tokenPromise->then(function ($tokenData) {
 echo "Streaming token obtained asynchronously\n";
 echo "Expires: {$tokenData['expires_at']}\n";
 
 // Setup WebSocket connection asynchronously
 return $this->setupWebSocketAsync($tokenData);
})
->then(function ($wsConnection) {
 echo "WebSocket connected asynchronously\n";
 
 // Subscribe to multiple channels concurrently
 $subscriptions = [
 'stocks.quotes' => ['AAPL', 'GOOGL', 'MSFT'],
 'signals' => ['min_confidence' => 80],
 'market.status' => []
 ];
 
 foreach ($subscriptions as $channel => $params) {
 $wsConnection->subscribeAsync($channel, $params);
 }
})
->catch(function ($error) {
 echo "Streaming setup failed: {$error}\n";
});

// 7. Promise combinators for complex workflows
echo "\n7. Promise Combinators:\n";

// Promise.all equivalent - wait for all
$allPromises = [
 $asyncClient->stocks()->quoteAsync('AAPL'),
 $asyncClient->stocks()->quoteAsync('GOOGL'),
 $asyncClient->markets()->statusAsync()
];

$allResults = Promise::all($allPromises)->wait();
echo "Promise::all completed - all " . count($allResults) . " operations successful\n";

// Promise.race equivalent - first to complete
$racePromises = [
 $asyncClient->stocks()->searchAsync('Apple'),
 $asyncClient->stocks()->searchAsync('Google'),
 $asyncClient->stocks()->searchAsync('Microsoft')
];

$firstResult = Promise::race($racePromises)->wait();
echo "Promise::race completed - first search returned results\n";

// Promise.any equivalent - first successful
$anyPromises = [
 $asyncClient->stocks()->quoteAsync('INVALID_SYMBOL'), // Will fail
 $asyncClient->stocks()->quoteAsync('AAPL'), // Will succeed
 $asyncClient->stocks()->quoteAsync('GOOGL') // Will succeed
];

$anyResult = Promise::any($anyPromises)->wait();
echo "Promise::any completed - first successful operation finished\n\n";

// 8. Memory and resource management
echo "8. Resource Management:\n";

// Monitor async operations
$eventLoop = $asyncClient->getEventLoop();
$loopStats = $eventLoop->getStatistics();

echo "Event Loop Statistics:\n";
echo "Active operations: {$loopStats['active_operations']}\n";
echo "⏳ Pending promises: {$loopStats['pending_promises']}\n";
echo "Memory usage: " . number_format($loopStats['memory_usage'] / 1024, 1) . " KB\n";
echo "Operations/sec: " . number_format($loopStats['operations_per_second'], 1) . "\n";

// Cleanup and optimization
if ($loopStats['memory_usage'] > 50 * 1024 * 1024) { // 50MB threshold
 echo "High memory usage detected, cleaning up...\n";
 $asyncClient->cleanup();
 echo "Cleanup completed\n";
}

// Graceful shutdown
$asyncClient->shutdown(5); // 5 second graceful shutdown
echo "Async client shutdown completed\n";

echo "\n9. Async Performance Summary:\n";
echo "Concurrent execution: 3-10x performance improvement\n";
echo "Resource efficiency: Better CPU and network utilization\n";
echo "Scalability: Handle hundreds of concurrent operations\n";
echo "Reliability: Built-in error recovery and timeouts\n";

Performance & Best Practices

// 1. Optimal SDK Configuration for Production
echo "Production Optimization Guide:\n\n";

// Production-ready client configuration
$optimizedClient = new WioexClient([
 'api_key' => getenv('WIOEX_API_KEY'),
 'base_url' => 'https://api.wioex.com',
 
 // Performance optimizations
 'timeout' => 30,
 'connect_timeout' => 10,
 
 // Retry strategy for reliability
 'retry' => [
 'times' => 3,
 'delay' => 200, // Start with 200ms
 'multiplier' => 2, // Exponential backoff
 'max_delay' => 5000, // Cap at 5 seconds
 'jitter' => true // Add randomization
 ],
 
 // Connection pooling for efficiency
 'connection_pool' => [
 'max_connections' => 10,
 'max_per_host' => 5,
 'idle_timeout' => 30,
 'keep_alive' => true
 ],
 
 // Advanced caching configuration
 'cache' => [
 'default' => 'memory',
 'drivers' => [
 'memory' => [
 'driver' => 'memory',
 'config' => [
 'max_items' => 1000,
 'ttl_variance' => 0.1 // 10% TTL variance to prevent cache stampedes
 ]
 ],
 'redis' => [
 'driver' => 'redis',
 'config' => [
 'host' => '127.0.0.1',
 'port' => 6379,
 'prefix' => 'wioex_cache:'
 ]
 ]
 ]
 ],
 
 // Rate limiting configuration
 'rate_limiting' => [
 'enabled' => true,
 'requests' => 100,
 'window' => 60,
 'strategy' => 'sliding_window',
 'burst_allowance' => 20
 ]
]);

echo "1. Optimized Client Configuration:\n";
echo "Connection pooling enabled\n";
echo "Intelligent retry strategy\n";
echo "Advanced caching configured\n";
echo "Rate limiting configured\n\n";

// 2. Performance monitoring and metrics
echo "2. Performance Monitoring:\n";

class PerformanceMonitor
{
 private $metrics = [];
 private $startTimes = [];
 
 public function startOperation(string $operation): void
 {
 $this->startTimes[$operation] = microtime(true);
 }
 
 public function endOperation(string $operation, bool $success = true): void
 {
 if (!isset($this->startTimes[$operation])) return;
 
 $duration = (microtime(true) - $this->startTimes[$operation]) * 1000;
 
 if (!isset($this->metrics[$operation])) {
 $this->metrics[$operation] = [
 'count' => 0,
 'total_time' => 0,
 'min_time' => PHP_FLOAT_MAX,
 'max_time' => 0,
 'success_count' => 0,
 'error_count' => 0
 ];
 }
 
 $metric = &$this->metrics[$operation];
 $metric['count']++;
 $metric['total_time'] += $duration;
 $metric['min_time'] = min($metric['min_time'], $duration);
 $metric['max_time'] = max($metric['max_time'], $duration);
 
 if ($success) {
 $metric['success_count']++;
 } else {
 $metric['error_count']++;
 }
 
 unset($this->startTimes[$operation]);
 }
 
 public function getReport(): array
 {
 $report = [];
 foreach ($this->metrics as $operation => $metric) {
 $avgTime = $metric['count'] > 0 ? $metric['total_time'] / $metric['count'] : 0;
 $successRate = $metric['count'] > 0 ? ($metric['success_count'] / $metric['count']) * 100 : 0;
 
 $report[$operation] = [
 'calls' => $metric['count'],
 'avg_time' => round($avgTime, 2),
 'min_time' => round($metric['min_time'], 2),
 'max_time' => round($metric['max_time'], 2),
 'success_rate' => round($successRate, 1),
 'total_time' => round($metric['total_time'], 2)
 ];
 }
 return $report;
 }
}

$monitor = new PerformanceMonitor();

// Monitor API operations
$operations = ['quote_AAPL', 'quote_GOOGL', 'quote_MSFT'];
foreach ($operations as $op) {
 $symbol = substr($op, 6); // Extract symbol
 
 $monitor->startOperation($op);
 try {
 $result = $optimizedClient->stocks()->quote($symbol);
 $monitor->endOperation($op, true);
 echo "{$symbol}: $" . number_format($result['tickers'][0]['market']['price'], 2) . "\n";
 } catch (Exception $e) {
 $monitor->endOperation($op, false);
 echo "{$symbol}: Failed\n";
 }
}

// Display performance report
$report = $monitor->getReport();
echo "\n Performance Report:\n";
foreach ($report as $operation => $stats) {
 printf("%-12s: %d calls, %.1fms avg, %.1f%% success\n",
 $operation,
 $stats['calls'],
 $stats['avg_time'],
 $stats['success_rate']
 );
}

// 3. Memory optimization techniques
echo "\n3. Memory Optimization:\n";

// Memory-efficient data processing
function processLargeDataset(array $symbols, $client): void
{
 $initialMemory = memory_get_usage(true);
 echo "Initial memory: " . number_format($initialMemory / 1024, 1) . " KB\n";
 
 // Process in chunks to avoid memory bloat
 $chunkSize = 5;
 $chunks = array_chunk($symbols, $chunkSize);
 
 foreach ($chunks as $chunkIndex => $chunk) {
 // Process chunk
 $quotes = $client->stocks()->quote(implode(',', $chunk));
 
 // Process data immediately and discard
 foreach ($quotes['tickers'] as $ticker) {
 // Process ticker data here
 $price = $ticker['market']['price'];
 // ... processing logic
 }
 
 // Force garbage collection after processing
 unset($quotes);
 if ($chunkIndex % 3 === 0) { // Every 3 chunks
 gc_collect_cycles();
 }
 
 $currentMemory = memory_get_usage(true);
 echo "Chunk " . ($chunkIndex + 1) . " memory: " . number_format($currentMemory / 1024, 1) . " KB\n";
 }
 
 $finalMemory = memory_get_usage(true);
 $memoryIncrease = $finalMemory - $initialMemory;
 echo "Memory increase: " . number_format($memoryIncrease / 1024, 1) . " KB\n";
}

$largeSymbolList = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA', 'META', 'NVDA', 'AMD', 'CRM', 'NFLX'];
processLargeDataset($largeSymbolList, $optimizedClient);

// 4. Advanced rate limiting and throttling
echo "\n4. Advanced Rate Limiting:\n";

class AdaptiveRateLimiter
{
 private $requestTimes = [];
 private $errorCount = 0;
 private $maxErrorsBeforeSlowdown = 3;
 private $baseDelay = 100; // milliseconds
 
 public function shouldDelay(): int
 {
 // Remove old requests (older than 1 minute)
 $cutoff = time() - 60;
 $this->requestTimes = array_filter($this->requestTimes, fn($time) => $time > $cutoff);
 
 // Calculate current rate
 $currentRate = count($this->requestTimes);
 
 // Adaptive delay based on error rate and current load
 $errorMultiplier = min(pow(2, $this->errorCount), 8); // Cap at 8x
 $loadMultiplier = $currentRate > 50 ? 2 : 1;
 
 return (int)($this->baseDelay * $errorMultiplier * $loadMultiplier);
 }
 
 public function recordRequest(bool $success = true): void
 {
 $this->requestTimes[] = time();
 
 if ($success) {
 $this->errorCount = max(0, $this->errorCount - 1); // Decay error count
 } else {
 $this->errorCount++;
 }
 }
 
 public function getStatistics(): array
 {
 return [
 'requests_last_minute' => count($this->requestTimes),
 'error_count' => $this->errorCount,
 'current_delay' => $this->shouldDelay()
 ];
 }
}

$rateLimiter = new AdaptiveRateLimiter();

for ($i = 0; $i < 5; $i++) {
 $delay = $rateLimiter->shouldDelay();
 if ($delay > 0) {
 echo "⏳ Adaptive delay: {$delay}ms\n";
 usleep($delay * 1000); // Convert to microseconds
 }
 
 // Simulate API call
 $success = rand(0, 10) > 2; // 80% success rate
 $rateLimiter->recordRequest($success);
 
 echo "" . ($success ? "" : "") . " Request " . ($i + 1) . "\n";
}

$stats = $rateLimiter->getStatistics();
echo "Rate Limiter Stats: {$stats['requests_last_minute']} req/min, {$stats['error_count']} errors, {$stats['current_delay']}ms delay\n";

// 5. Efficient error handling and recovery
echo "\n5. Error Handling Best Practices:\n";

class RobustApiClient
{
 private $client;
 private $circuitBreaker;
 private $retryCount = 0;
 private $maxRetries = 3;
 
 public function __construct($client)
 {
 $this->client = $client;
 $this->circuitBreaker = ['failures' => 0, 'lastFailure' => 0, 'state' => 'closed'];
 }
 
 public function safeQuote(string $symbol): ?array
 {
 // Check circuit breaker
 if ($this->isCircuitOpen()) {
 echo "Circuit breaker open for {$symbol}\n";
 return $this->getFallbackData($symbol);
 }
 
 try {
 $result = $this->client->stocks()->quote($symbol);
 $this->onSuccess();
 return $result;
 
 } catch (RateLimitException $e) {
 echo "Rate limited, backing off...\n";
 $waitTime = $e->getRetryAfter() ?? (pow(2, $this->retryCount) * 1000);
 usleep($waitTime * 1000);
 
 if ($this->retryCount < $this->maxRetries) {
 $this->retryCount++;
 return $this->safeQuote($symbol);
 }
 
 } catch (Exception $e) {
 $this->onFailure();
 echo "Error for {$symbol}: " . substr($e->getMessage(), 0, 50) . "\n";
 return $this->getFallbackData($symbol);
 }
 
 return null;
 }
 
 private function isCircuitOpen(): bool
 {
 if ($this->circuitBreaker['state'] === 'open') {
 // Check if enough time has passed to try again
 if (time() - $this->circuitBreaker['lastFailure'] > 30) {
 $this->circuitBreaker['state'] = 'half-open';
 return false;
 }
 return true;
 }
 return false;
 }
 
 private function onSuccess(): void
 {
 $this->circuitBreaker['failures'] = 0;
 $this->circuitBreaker['state'] = 'closed';
 $this->retryCount = 0;
 }
 
 private function onFailure(): void
 {
 $this->circuitBreaker['failures']++;
 $this->circuitBreaker['lastFailure'] = time();
 
 if ($this->circuitBreaker['failures'] >= 5) {
 $this->circuitBreaker['state'] = 'open';
 echo "Circuit breaker opened due to failures\n";
 }
 }
 
 private function getFallbackData(string $symbol): array
 {
 // Return cached or default data
 return [
 'symbol' => $symbol,
 'price' => 100.00, // Fallback price
 'source' => 'fallback',
 'timestamp' => time()
 ];
 }
}

$robustClient = new RobustApiClient($optimizedClient);

// Test with some symbols
$testSymbols = ['AAPL', 'GOOGL', 'INVALID_SYMBOL'];
foreach ($testSymbols as $symbol) {
 $result = $robustClient->safeQuote($symbol);
 if ($result) {
 $price = $result['tickers'][0]['market']['price'] ?? $result['price'];
 echo "{$symbol}: $" . number_format($price, 2) . "\n";
 }
}

// 6. Optimized data fetching patterns
echo "\n6. Optimized Data Fetching:\n";

// Smart batching strategy
function optimizedPortfolioFetch(array $symbols, $client): array
{
 $startTime = microtime(true);
 
 // Group symbols for optimal batch sizes
 $prioritySymbols = array_slice($symbols, 0, 5); // High priority
 $regularSymbols = array_slice($symbols, 5); // Regular priority
 
 $results = [];
 
 // Fetch priority symbols first with smaller batches
 if (!empty($prioritySymbols)) {
 echo "Fetching priority symbols...\n";
 $priorityQuotes = $client->stocks()->quote(implode(',', $prioritySymbols));
 $results['priority'] = $priorityQuotes;
 }
 
 // Fetch regular symbols with larger batches
 if (!empty($regularSymbols)) {
 echo "Fetching regular symbols...\n";
 $chunks = array_chunk($regularSymbols, 10); // Larger batches for regular data
 
 foreach ($chunks as $chunk) {
 $quotes = $client->stocks()->quote(implode(',', $chunk));
 $results['regular'][] = $quotes;
 
 // Small delay between chunks to respect rate limits
 usleep(50000); // 50ms
 }
 }
 
 $totalTime = (microtime(true) - $startTime) * 1000;
 echo "Optimized fetch completed in " . number_format($totalTime, 2) . "ms\n";
 
 return $results;
}

$portfolioResults = optimizedPortfolioFetch($largeSymbolList, $optimizedClient);

// 7. Performance benchmarking
echo "\n7. Performance Benchmarking:\n";

function benchmarkOperations($client): array
{
 $benchmarks = [];
 
 // Benchmark different operation types
 $operations = [
 'single_quote' => fn() => $client->stocks()->quote('AAPL'),
 'multi_quote' => fn() => $client->stocks()->quote('AAPL,GOOGL,MSFT'),
 'company_info' => fn() => $client->stocks()->info('AAPL'),
 'market_status' => fn() => $client->markets()->status(),
 ];
 
 foreach ($operations as $name => $operation) {
 $times = [];
 
 // Run each operation 5 times
 for ($i = 0; $i < 5; $i++) {
 $start = microtime(true);
 try {
 $operation();
 $times[] = (microtime(true) - $start) * 1000;
 } catch (Exception $e) {
 // Skip failed operations
 }
 }
 
 if (!empty($times)) {
 $benchmarks[$name] = [
 'avg' => array_sum($times) / count($times),
 'min' => min($times),
 'max' => max($times),
 'count' => count($times)
 ];
 }
 }
 
 return $benchmarks;
}

$benchmarks = benchmarkOperations($optimizedClient);
foreach ($benchmarks as $operation => $stats) {
 printf("%-15s: %.1fms avg (%.1f-%.1fms range)\n",
 $operation,
 $stats['avg'],
 $stats['min'],
 $stats['max']
 );
}

// 8. Production deployment checklist
echo "\n8. Production Deployment Checklist:\n";

$productionChecklist = [
 'API Key Configuration' => getenv('WIOEX_API_KEY') !== false,
 'Caching Enabled' => $optimizedClient->getCache() !== null,
 'Error Logging' => function_exists('error_log'),
 'Memory Limit' => (int)ini_get('memory_limit') >= 256,
 'Timeout Configuration' => true, // Already configured above
 'Rate Limiting' => true, // Already configured above
 'SSL Verification' => true // Assuming HTTPS is properly configured
];

foreach ($productionChecklist as $item => $status) {
 $emoji = $status ? '' : '';
 echo "{$emoji} {$item}\n";
}

echo "\n9. Performance Summary:\n";
echo "Optimized for production workloads\n";
echo "Comprehensive monitoring and metrics\n";
echo "Robust error handling and recovery\n";
echo "Efficient resource utilization\n";
echo "Adaptive rate limiting and throttling\n";
echo "Memory-optimized data processing\n";
echo "Performance benchmarking and analysis\n";

New Export Utilities (v2.0.0)

Export data in multiple formats:

use Wioex\SDK\Export\ExportManager;
use Wioex\SDK\Enums\ExportFormat;

$exportManager = new ExportManager();

// Get stock data
$stockData = $client->stocks()->quote('AAPL,GOOGL,MSFT');

// Export to different formats
$exportManager->exportToFile($stockData, ExportFormat::JSON, 'stocks.json');
$exportManager->exportToFile($stockData, ExportFormat::CSV, 'stocks.csv');

// Export to string
$csvString = $exportManager->export($stockData, ExportFormat::CSV);

// Multiple formats at once
$results = $exportManager->exportMultipleFormats(
 $stockData, 
 [ExportFormat::JSON, ExportFormat::CSV], 
 'export_base_name'
);

Configuration

Basic Setup

$client = new WioexClient([
 'api_key' => 'your-api-key-here'
]);

Advanced Configuration

use Wioex\SDK\Enums\ErrorReportingLevel;

$client = new WioexClient([
 'api_key' => 'your-api-key-here',
 'timeout' => 30,
 'connect_timeout' => 10,
 'error_reporting' => true,
 'error_reporting_level' => ErrorReportingLevel::STANDARD,
 'retry' => [
 'times' => 3,
 'delay' => 100,
 'multiplier' => 2
 ]
]);

Environment-Based Configuration (New)

use Wioex\SDK\Enums\Environment;

// Load from environment
$client = WioexClient::fromEnvironment(Environment::PRODUCTION);

// Load from config file
$client = WioexClient::fromConfig('config/wioex.php');

// Dynamic configuration
$client->configure([
 'timeout' => 60,
 'debug' => true
]);

Error Handling

use Wioex\SDK\Exceptions\{
 AuthenticationException,
 ValidationException,
 RateLimitException,
 ServerException,
 RequestException
};

try {
 $stock = $client->stocks()->quote('AAPL');
 
 if ($stock->successful()) {
 // Process data
 $data = $stock->data();
 }
 
} catch (AuthenticationException $e) {
 echo "Authentication failed: " . $e->getMessage();
} catch (ValidationException $e) {
 echo "Validation error: " . $e->getMessage();
} catch (RateLimitException $e) {
 echo "Rate limit exceeded. Retry after: " . $e->getRetryAfter() . " seconds";
} catch (ServerException $e) {
 echo "Server error: " . $e->getMessage();
} catch (RequestException $e) {
 echo "Request failed: " . $e->getMessage();
}

Response Handling

$response = $client->stocks()->quote('AAPL');

// Check status
if ($response->successful()) {
 // Get data
 $data = $response->data();
 $ticker = $response['tickers'][0];
 
 // Array access
 echo $ticker['market']['price'];
 
 // Get as JSON
 $json = $response->json();
}

// Response methods
$response->status(); // HTTP status code
$response->successful(); // true if 2xx
$response->failed(); // true if not 2xx
$response->headers(); // All headers
$response->header('Name'); // Specific header

Testing

The SDK includes comprehensive testing:

# Run all tests
composer test

# Run with coverage
composer test:coverage

# Static analysis
composer phpstan

# Code style
composer cs:check
composer cs:fix

Test Coverage:

  • 135+ unit tests
  • Core classes: 100% coverage
  • Resources: 95%+ coverage
  • Error handling: 100% coverage

Migration from v1.x

Zero breaking changes! Your existing code works without modifications:

// All these calls work exactly the same
$client->stocks()->quote('AAPL'); // Works
$client->streaming()->getToken(); // Fixed in v2.0.0
$client->markets()->status(); // Works
$client->account()->balance(); // Works

New optional features:

  • Export utilities for data export
  • Environment-based configuration
  • Enhanced error reporting

πŸš€ Ticker Analysis (NEW in v2.4.0)

Comprehensive investment research with institutional-grade analysis.

// Get comprehensive ticker analysis (5 credits)
$analysis = $client->stocks()->tickerAnalysis('AAPL');

if ($analysis->successful()) {
    // Analyst Ratings & Price Targets
    $analystRatings = $analysis->getAnalystRatings();
    echo "Analyst Consensus: " . $analystRatings['summary']['viewpoint'] . "\n";
    echo "Price Target: " . $analystRatings['summary']['price_target'] . "\n";
    
    // Earnings Insights & Performance
    $earnings = $analysis->getEarningsPerformance();
    echo "Earnings Outlook: " . $earnings['outlook'] . "\n";
    echo "Current Quarter: " . $earnings['fiscal_period'] . "\n";
    
    // Market Sentiment Analysis
    $sentiment = $analysis->getMarketSentiment();
    echo "News Sentiment: " . substr($sentiment['news_summary'], 0, 100) . "...\n";
    echo "Options P/C Ratio: " . $sentiment['put_call_ratio'] . "\n";
    
    // Insider Activity Tracking
    $insider = $analysis->getInsiderActivity();
    echo "Insider Activity: " . $insider['highlights'] . "\n";
    
    // Financial & Technical Metrics
    $priceMovement = $analysis->getPriceMovement();
    echo "Beta: " . $priceMovement['beta'] . "\n";
    echo "Sector: " . $priceMovement['sector'] . "\n";
    echo "Stock Performance: " . $priceMovement['stock_percentage_change'] . "%\n";
    
    // Professional Validation
    $validation = $analysis->validateTickerAnalysisResponse();
    echo $validation->isValid() ? "βœ… Analysis validation passed\n" : "❌ Validation failed\n";
    
    // Cost & Performance Tracking
    echo "Credits Used: " . $analysis->getCredits()['consumed'] . "\n";
    echo "Response Time: " . $analysis->getPerformance()['total_time_ms'] . "ms\n";
}

// Portfolio Analysis Example
$symbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'NVDA'];
foreach ($symbols as $symbol) {
    $analysis = $client->stocks()->tickerAnalysis($symbol);
    if ($analysis->successful()) {
        $ratings = $analysis->getAnalystRatings();
        $earnings = $analysis->getEarningsPerformance();
        
        echo "{$symbol}: " . ($ratings['summary']['viewpoint'] ?? 'No rating') . 
             " | Outlook: " . ($earnings['outlook'] ?? 'No data') . "\n";
    }
}

Ticker Analysis Features:

  • πŸ“ˆ Analyst Ratings: Price targets, recommendations, consensus
  • πŸ’Ό Earnings Insights: Quarterly results, guidance, call highlights
  • πŸ‘₯ Insider Activity: Executive transactions, sentiment analysis
  • πŸ“° News Analysis: Market sentiment, themes, key events
  • πŸ“Š Options Analysis: Put/call ratios, market implications
  • πŸ“ˆ Price Movement: Technical analysis, sector comparison
  • πŸ’° Financial Metrics: Valuation ratios, growth indicators
  • πŸ” Market Overview: Comprehensive summary and insights

Perfect for:

  • Investment research and due diligence
  • Portfolio analysis and optimization
  • Market sentiment tracking
  • Risk assessment and beta analysis
  • Options trading strategy development

Examples

See the /examples directory:

  • ticker-analysis-example.php - NEW: Comprehensive ticker analysis
  • stocks-example.php - Stock data operations
  • streaming-example.php - WebSocket streaming setup
  • market-status-example.php - Market hours and status
  • error-handling.php - Exception handling patterns
  • export-example.php - Data export examples
  • complete_integration_example.php - Full feature demonstration

Version History

  • v2.0.0 (2025-10-22) - Production ready release with critical fixes
  • v1.4.0 - Enhanced timeline and caching features
  • v1.3.0 - WebSocket streaming and API improvements
  • v1.2.0 - Session filtering and timeline enhancements
  • v1.1.0 - Trading signals and market status
  • v1.0.0 - Initial release

Support

Contributing

  1. Fork the repository
  2. Create your feature branch
  3. Run tests: composer test
  4. Commit changes
  5. Submit pull request

License

MIT License. See LICENSE for details.


Production Ready - All critical issues resolved in v2.0.0

Made by WioEX Team