2024-09-12 21:05:01 -05:00
|
|
|
<?php
|
|
|
|
|
|
2025-01-28 17:33:54 -06:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2024-09-12 21:05:01 -05:00
|
|
|
namespace App\Interfaces\MarketData;
|
|
|
|
|
|
2025-01-28 17:14:49 -06:00
|
|
|
use App\Interfaces\MarketData\Types\Dividend;
|
2024-10-29 16:34:18 -05:00
|
|
|
use App\Interfaces\MarketData\Types\Ohlc;
|
|
|
|
|
use App\Interfaces\MarketData\Types\Quote;
|
|
|
|
|
use App\Interfaces\MarketData\Types\Split;
|
2025-01-28 17:14:49 -06:00
|
|
|
use Illuminate\Support\Arr;
|
|
|
|
|
use Illuminate\Support\Carbon;
|
|
|
|
|
use Illuminate\Support\Collection;
|
2024-09-12 21:05:01 -05:00
|
|
|
|
|
|
|
|
class FinnhubMarketData implements MarketDataInterface
|
|
|
|
|
{
|
|
|
|
|
public \Finnhub\Api\DefaultApi $client;
|
|
|
|
|
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
2025-01-28 17:14:49 -06:00
|
|
|
|
2024-09-12 21:05:01 -05:00
|
|
|
$this->client = new \Finnhub\Api\DefaultApi(
|
2025-01-28 17:14:49 -06:00
|
|
|
new \GuzzleHttp\Client,
|
2024-09-12 21:05:01 -05:00
|
|
|
\Finnhub\Configuration::getDefaultConfiguration()->setApiKey('token', config('finnhub.key'))
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-01-28 17:14:49 -06:00
|
|
|
|
|
|
|
|
public function exists(string $symbol): bool
|
2024-09-12 21:05:01 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
return $this->quote($symbol)->isNotEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:34:18 -05:00
|
|
|
public function quote(string $symbol): Quote
|
2024-09-12 21:05:01 -05:00
|
|
|
{
|
|
|
|
|
$quote = $this->client->quote($symbol);
|
2024-10-29 16:34:18 -05:00
|
|
|
|
2025-01-28 17:14:49 -06:00
|
|
|
if (empty($quote)) {
|
|
|
|
|
return new Quote;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-23 13:43:34 -05:00
|
|
|
$fundamental = cache()->remember(
|
2025-01-28 17:14:49 -06:00
|
|
|
'fh-symbol-'.$symbol,
|
|
|
|
|
1440,
|
2024-09-12 21:05:01 -05:00
|
|
|
function () use ($symbol) {
|
2025-01-28 17:14:49 -06:00
|
|
|
return $this->client->companyBasicFinancials($symbol, 'all');
|
2024-09-12 21:05:01 -05:00
|
|
|
}
|
|
|
|
|
);
|
2025-01-28 17:14:49 -06:00
|
|
|
|
2024-10-29 16:34:18 -05:00
|
|
|
return new Quote([
|
2024-09-12 21:05:01 -05:00
|
|
|
'name' => Arr::get($fundamental, 'metric.name'),
|
|
|
|
|
'symbol' => $symbol,
|
2025-01-28 17:14:49 -06:00
|
|
|
'market_value' => Arr::get($quote, 'c'),
|
2024-10-29 16:34:18 -05:00
|
|
|
'fifty_two_week_high' => Arr::get($fundamental, 'metric.52WeekHigh'),
|
|
|
|
|
'fifty_two_week_low' => Arr::get($fundamental, 'metric.52WeekLow'),
|
|
|
|
|
'forward_pe' => Arr::get($fundamental, 'metric.forwardPE'), // confirm
|
|
|
|
|
'trailing_pe' => Arr::get($fundamental, 'metric.trailingPE'), // confirm
|
|
|
|
|
'market_cap' => Arr::get($fundamental, 'metric.marketCapitalization'), // confirm
|
|
|
|
|
'book_value' => Arr::get($fundamental, 'metric.bookValuePerShare'), // confirm
|
2024-09-12 21:05:01 -05:00
|
|
|
'last_dividend_date' => Arr::get($fundamental, 'metric.lastDivDate'), // confirm
|
2024-10-29 16:34:18 -05:00
|
|
|
'dividend_yield' => Arr::get($fundamental, 'metric.dividendYield'), // confirm
|
2025-01-28 17:14:49 -06:00
|
|
|
]);
|
2024-09-12 21:05:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function dividends($symbol, $startDate, $endDate): Collection
|
|
|
|
|
{
|
|
|
|
|
$dividends = $this->client->stockDividends($symbol, $startDate->format('Y-m-d'), $endDate->format('Y-m-d'));
|
2025-01-28 17:14:49 -06:00
|
|
|
|
|
|
|
|
return collect($dividends)->map(function ($dividend) use ($symbol) {
|
|
|
|
|
|
2024-10-29 16:34:18 -05:00
|
|
|
return new Dividend([
|
2024-09-12 21:05:01 -05:00
|
|
|
'symbol' => $symbol,
|
2024-10-29 16:34:18 -05:00
|
|
|
'date' => Carbon::parse(Arr::get($dividend, 'date')),
|
2024-09-12 21:05:01 -05:00
|
|
|
'dividend_amount' => Arr::get($dividend, 'amount'),
|
2024-10-29 16:34:18 -05:00
|
|
|
]);
|
2024-09-12 21:05:01 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function splits($symbol, $startDate, $endDate): Collection
|
2025-01-28 17:14:49 -06:00
|
|
|
{
|
2024-09-12 21:05:01 -05:00
|
|
|
|
|
|
|
|
$splits = $this->client->stockSplits($symbol, $startDate->format('Y-m-d'), $endDate->format('Y-m-d'));
|
|
|
|
|
|
2025-01-28 17:14:49 -06:00
|
|
|
return collect($splits)->map(function ($split) use ($symbol) {
|
|
|
|
|
|
2024-10-29 16:34:18 -05:00
|
|
|
return new Split([
|
2024-09-12 21:05:01 -05:00
|
|
|
'symbol' => $symbol,
|
2024-10-29 16:34:18 -05:00
|
|
|
'date' => Carbon::parse(Arr::get($split, 'date')),
|
2024-09-12 21:05:01 -05:00
|
|
|
'split_amount' => Arr::get($split, 'toFactor') / Arr::get($split, 'fromFactor'),
|
2024-10-29 16:34:18 -05:00
|
|
|
]);
|
2024-09-12 21:05:01 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function history($symbol, $startDate, $endDate): Collection
|
|
|
|
|
{
|
|
|
|
|
|
2025-01-28 17:14:49 -06:00
|
|
|
$history = $this->client->stockCandles($symbol, 'D', $startDate->timestamp, $endDate->timestamp);
|
2024-09-12 21:05:01 -05:00
|
|
|
|
|
|
|
|
$timestamps = Arr::get($history, 't', []);
|
|
|
|
|
$closes = Arr::get($history, 'c', []);
|
|
|
|
|
|
|
|
|
|
return collect($timestamps)->mapWithKeys(function ($timestamp, $index) use ($symbol, $closes) {
|
|
|
|
|
$date = Carbon::createFromTimestamp($timestamp)->format('Y-m-d');
|
2025-01-28 17:14:49 -06:00
|
|
|
|
|
|
|
|
return [$date => new Ohlc([
|
2024-09-12 21:05:01 -05:00
|
|
|
'symbol' => $symbol,
|
|
|
|
|
'date' => $date,
|
2024-10-29 16:34:18 -05:00
|
|
|
'close' => $closes[$index],
|
2025-01-28 17:14:49 -06:00
|
|
|
])];
|
2024-09-12 21:05:01 -05:00
|
|
|
});
|
|
|
|
|
}
|
2025-01-28 17:14:49 -06:00
|
|
|
}
|