windy-network / client-php
Official PHP client SDK for the Windy Network API
Installs: 8
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/windy-network/client-php
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.5
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1|^2.0
- psr/log: ^2.0|^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.40
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- php-http/mock-client: ^1.6
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0|^11.0
Suggests
- illuminate/support: Required for Laravel integration (^10.0|^11.0|^12.0)
- symfony/http-kernel: Required for Symfony bundle (^6.0|^7.0)
- textalk/websocket: Required for WebSocket streaming (^1.6)
README
Official PHP SDK for the Windy Network API. Provides typed access to crypto, stocks, forex, options, and calendar market data with built-in authentication, retries, and real-time streaming.
Requirements
- PHP 8.1+
- Composer
Installation
composer require windy-network/client-php
Quick Start
use WindyNetwork\WindyClient; $client = WindyClient::create('your-api-key'); // Crypto rates $btc = $client->crypto->getRate('BTC', 'USD'); echo "BTC/USD: ${$btc->rate}"; // Stock quotes $aapl = $client->stocks->getQuote('AAPL'); echo "AAPL: ${$aapl->price}"; // Forex rates $eurusd = $client->forex->getRate('EUR', 'USD'); echo "EUR/USD: {$eurusd->rate}";
Configuration
use WindyNetwork\Config; use WindyNetwork\WindyClient; $client = WindyClient::create(new Config( apiKey: 'your-api-key', baseUrl: 'https://api.windy.network', timeout: 30, retries: 3, debug: true, ));
Authentication
API Key
$client = WindyClient::create('your-api-key');
Basic Auth
use WindyNetwork\Config; use WindyNetwork\Enums\AuthType; $client = WindyClient::create(new Config( authType: AuthType::Basic, username: 'user', password: 'pass', ));
OAuth 2.0
use WindyNetwork\Config; use WindyNetwork\Enums\AuthType; $client = WindyClient::create(new Config( authType: AuthType::OAuth, clientId: 'your-client-id', clientSecret: 'your-client-secret', )); // Client credentials grant $auth = $client->getAuthProvider(); $token = $auth->clientCredentialsGrant(['crypto:read', 'stock:read']); // Authorization code grant with PKCE use WindyNetwork\Auth\OAuthClient; $codeVerifier = OAuthClient::generateCodeVerifier(); $codeChallenge = OAuthClient::generateCodeChallenge($codeVerifier); $authUrl = $auth->getAuthorizationUrl([ 'state' => bin2hex(random_bytes(16)), 'code_challenge' => $codeChallenge, 'code_challenge_method' => 'S256', ]); // After redirect: $token = $auth->exchangeCode($code, $redirectUri, $codeVerifier);
API Endpoints
System
$health = $client->system->health(); $time = $client->system->time(); $version = $client->system->version();
Crypto
use WindyNetwork\Enums\Timeframe; // Rates $rate = $client->crypto->getRate('BTC', 'USD'); $rates = $client->crypto->getRates('basecoin'); // OHLC candlestick data $ohlc = $client->crypto->getOHLC('BTC', 'USD', Timeframe::H1, ['limit' => 24]); // Technical indicators $rsi = $client->crypto->getRSI('BTC', 'USD', Timeframe::D1, ['period' => 14]); $sma = $client->crypto->getSMA('BTC', 'USD', Timeframe::D1, ['period' => 20]); $ema = $client->crypto->getEMA('BTC', 'USD', Timeframe::D1, ['period' => 12]); $macd = $client->crypto->getMACD('BTC', 'USD', Timeframe::D1); $bb = $client->crypto->getBollingerBands('BTC', 'USD', Timeframe::D1); // Tickers & orderbook $ticker = $client->crypto->getTicker('binance', 'BTC', 'USD'); $orderbook = $client->crypto->getOrderbook('BTC', 'USD'); // Market data $gainers = $client->crypto->getGainers(); $losers = $client->crypto->getLosers(); $summary = $client->crypto->getMarketSummary(); // Assets & exchanges $assets = $client->crypto->getAssets(); $exchanges = $client->crypto->getExchanges();
Stocks
$quote = $client->stocks->getQuote('AAPL'); $quotes = $client->stocks->getQuotes(['AAPL', 'GOOGL', 'MSFT']); $ohlc = $client->stocks->getOHLC('AAPL', Timeframe::D1, ['limit' => 30]);
Forex
$rate = $client->forex->getRate('EUR', 'USD'); $rates = $client->forex->getRates(); $ohlc = $client->forex->getOHLC('EUR', 'USD', Timeframe::H1, ['limit' => 24]);
Options
$chain = $client->options->getChain('AAPL', ['expiration' => '2025-01-17']);
Calendar
$status = $client->calendar->getStatus(); $sessions = $client->calendar->getForexSessions(); $exchanges = $client->calendar->getExchanges(); $holidays = $client->calendar->getMarketHolidays(['market' => 'US']);
User (Authenticated)
// Alerts $alerts = $client->user->getAlerts(); $alert = $client->user->createAlert([...]); $client->user->deleteAlert($alertId); // Watchlists $watchlists = $client->user->getWatchlists(); $watchlist = $client->user->createWatchlist([...]); // Portfolio $portfolios = $client->user->getPortfolios(); $positions = $client->user->getPositions($portfolioId);
Real-Time Streaming
Server-Sent Events (SSE)
$sse = $client->sse(); $sse->on('connect', fn() => echo "Connected\n"); $sse->on('error', fn(\Throwable $e) => echo "Error: {$e->getMessage()}\n"); $channels = [ 'crypto:rate:basecoin:BTC:USD', 'crypto:rate:basecoin:ETH:USD', ]; $sse->connect($channels, function ($message) { echo "[{$message->channel}] " . json_encode($message->data) . "\n"; });
HTTP Polling
$poller = $client->polling(['interval' => 5]); $poller->connect(['crypto:rate:basecoin:BTC:USD'], function ($message) { echo json_encode($message->data) . "\n"; });
WebSocket
Requires the optional textalk/websocket package:
composer require textalk/websocket
$ws = $client->websocket(); $ws->connect(['crypto:rate:basecoin:BTC:USD'], function ($message) { echo json_encode($message->data) . "\n"; });
Error Handling
use WindyNetwork\Exceptions\AuthenticationException; use WindyNetwork\Exceptions\RateLimitException; use WindyNetwork\Exceptions\ValidationException; use WindyNetwork\Exceptions\ApiException; use WindyNetwork\Exceptions\WindyException; try { $rate = $client->crypto->getRate('BTC', 'USD'); } catch (AuthenticationException $e) { // Invalid API key (401) } catch (RateLimitException $e) { // Too many requests (429) sleep($e->retryAfter); } catch (ValidationException $e) { // Bad request (400) $details = $e->details; } catch (ApiException $e) { // Other HTTP errors echo "Status: {$e->statusCode}, Request ID: {$e->requestId}"; } catch (WindyException $e) { // SDK-level errors } // Check if an error is retryable if (WindyException::isRetryable($e)) { // Retry the request }
Rate Limiting
Rate limit info is available after each request:
$rateLimit = $client->getHttpClient()->getRateLimit(); if ($rateLimit) { echo "Remaining: {$rateLimit->remaining}/{$rateLimit->limit}"; }
The SDK automatically retries on 429 responses with exponential backoff.
Laravel Integration
Setup
composer require windy-network/client-php php artisan vendor:publish --tag=windy-config
Add to your .env:
WINDY_API_KEY=your-api-key
Usage
// Dependency injection class CryptoController extends Controller { public function __construct( private readonly WindyClient $windy, ) {} public function rate(string $base, string $quote) { return response()->json( $this->windy->crypto->getRate($base, $quote) ); } } // Facade use WindyNetwork\Laravel\WindyFacade as Windy; $rate = Windy::crypto->getRate('BTC', 'USD'); // Helper $client = app(\WindyNetwork\WindyClient::class);
Symfony Integration
Configuration
# config/packages/windy.yaml windy: api_key: '%env(WINDY_API_KEY)%' base_url: 'https://api.windy.network' timeout: 30 retries: 3
Usage
class CryptoController extends AbstractController { public function __construct( private readonly WindyClient $windy, ) {} #[Route('/rate/{base}/{quote}')] public function rate(string $base, string $quote): JsonResponse { $rate = $this->windy->crypto->getRate($base, $quote); return $this->json($rate); } }
Testing
# Unit tests vendor/bin/phpunit --testsuite=Unit # Integration tests (requires API key) WINDY_API_KEY=your-key vendor/bin/phpunit --testsuite=Integration # Static analysis vendor/bin/phpstan analyse # Code style vendor/bin/php-cs-fixer fix --dry-run
Examples
See the examples/ directory:
- basic-usage.php - API key setup, rates, OHLC, indicators
- oauth-flow.php - OAuth grants, PKCE, token management
- streaming-sse.php - Real-time SSE streaming
- error-handling.php - Exception patterns
- laravel-example.php - Laravel DI, facade, config
License
MIT