feat:create custom data types for market data
This commit is contained in:
@@ -5,6 +5,10 @@ namespace App\Interfaces\MarketData;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
use App\Interfaces\MarketData\Types\Split;
|
||||
use App\Interfaces\MarketData\Types\Dividend;
|
||||
use App\Interfaces\MarketData\Types\Ohlc;
|
||||
use Tschucki\Alphavantage\Facades\Alphavantage;
|
||||
|
||||
class AlphaVantageMarketData implements MarketDataInterface
|
||||
@@ -15,11 +19,13 @@ class AlphaVantageMarketData implements MarketDataInterface
|
||||
return $this->quote($symbol)->isNotEmpty();
|
||||
}
|
||||
|
||||
public function quote(String $symbol): Collection
|
||||
public function quote(String $symbol): Quote
|
||||
{
|
||||
$quote = Alphavantage::core()->quoteEndpoint($symbol);
|
||||
$quote = Arr::get($quote, 'Global Quote', []);
|
||||
|
||||
if (empty($quote)) return new Quote();
|
||||
|
||||
$fundamental = cache()->remember(
|
||||
'av-symbol-'.$symbol,
|
||||
1440,
|
||||
@@ -28,21 +34,21 @@ class AlphaVantageMarketData implements MarketDataInterface
|
||||
}
|
||||
);
|
||||
|
||||
return collect([
|
||||
return new Quote([
|
||||
'name' => Arr::get($fundamental, 'Name'),
|
||||
'symbol' => Arr::get($fundamental, 'Symbol'),
|
||||
'market_value' => (float) Arr::get($quote, '05. price'),
|
||||
'fifty_two_week_high' => (float) Arr::get($fundamental, '52WeekHigh'),
|
||||
'fifty_two_week_low' => (float) Arr::get($fundamental, '52WeekLow'),
|
||||
'forward_pe' => (float) Arr::get($fundamental, 'ForwardPE'),
|
||||
'trailing_pe' => (float) Arr::get($fundamental, 'TrailingPE'),
|
||||
'market_cap' => (int) Arr::get($fundamental, 'MarketCapitalization'),
|
||||
'book_value' => (float) Arr::get($fundamental, 'BookValue'),
|
||||
'market_value' => Arr::get($quote, '05. price'),
|
||||
'fifty_two_week_high' => Arr::get($fundamental, '52WeekHigh'),
|
||||
'fifty_two_week_low' => Arr::get($fundamental, '52WeekLow'),
|
||||
'forward_pe' => Arr::get($fundamental, 'ForwardPE'),
|
||||
'trailing_pe' => Arr::get($fundamental, 'TrailingPE'),
|
||||
'market_cap' => Arr::get($fundamental, 'MarketCapitalization'),
|
||||
'book_value' => Arr::get($fundamental, 'BookValue'),
|
||||
'last_dividend_date' => Arr::get($fundamental, 'DividendDate') != 'None'
|
||||
? Arr::get($fundamental, 'DividendDate')
|
||||
: null,
|
||||
'dividend_yield' => Arr::get($fundamental, 'DividendYield') != 'None'
|
||||
? (float) Arr::get($fundamental, 'DividendYield')
|
||||
? Arr::get($fundamental, 'DividendYield')
|
||||
: null
|
||||
]);
|
||||
}
|
||||
@@ -59,12 +65,11 @@ class AlphaVantageMarketData implements MarketDataInterface
|
||||
})
|
||||
->map(function($dividend) use ($symbol) {
|
||||
|
||||
return [
|
||||
return new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => Carbon::parse(Arr::get($dividend, 'ex_dividend_date'))
|
||||
->format('Y-m-d H:i:s'),
|
||||
'date' => Carbon::parse(Arr::get($dividend, 'ex_dividend_date')),
|
||||
'dividend_amount' => Arr::get($dividend, 'amount'),
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,12 +85,11 @@ class AlphaVantageMarketData implements MarketDataInterface
|
||||
})
|
||||
->map(function($split) use ($symbol) {
|
||||
|
||||
return [
|
||||
return new Split([
|
||||
'symbol' => $symbol,
|
||||
'date' => Carbon::parse(Arr::get($split, 'effective_date'))
|
||||
->format('Y-m-d H:i:s'),
|
||||
'date' => Carbon::parse(Arr::get($split, 'effective_date')),
|
||||
'split_amount' => Arr::get($split, 'split_factor'),
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,11 +109,11 @@ class AlphaVantageMarketData implements MarketDataInterface
|
||||
|
||||
$date = Carbon::parse($date)->format('Y-m-d');
|
||||
|
||||
return [ $date => [
|
||||
return [ $date => new Ohlc([
|
||||
'symbol' => $symbol,
|
||||
'date' => $date,
|
||||
'close' => (float) Arr::get($history, '4. close')
|
||||
]];
|
||||
'close' => Arr::get($history, '4. close')
|
||||
]) ];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,10 @@ namespace App\Interfaces\MarketData;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
use App\Interfaces\MarketData\Types\Dividend;
|
||||
use App\Interfaces\MarketData\Types\Ohlc;
|
||||
use App\Interfaces\MarketData\Types\Split;
|
||||
|
||||
class FakeMarketData implements MarketDataInterface
|
||||
{
|
||||
@@ -13,21 +17,21 @@ class FakeMarketData implements MarketDataInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
public function quote(String $symbol): Collection
|
||||
public function quote(String $symbol): Quote
|
||||
{
|
||||
|
||||
return collect([
|
||||
return new Quote([
|
||||
'name' => 'ACME Company Ltd',
|
||||
'symbol' => $symbol,
|
||||
'market_value' => (float) 230.19,
|
||||
'fifty_two_week_high' => (float) 512.90,
|
||||
'fifty_two_week_low' => (float) 341.20,
|
||||
'forward_pe' => (float) 20.1,
|
||||
'trailing_pe' => (float) 30.34,
|
||||
'market_cap' => (int) 9800700600,
|
||||
'book_value' => (float) 4.7,
|
||||
'market_value' => 230.19,
|
||||
'fifty_two_week_high' => 512.90,
|
||||
'fifty_two_week_low' => 341.20,
|
||||
'forward_pe' => 20.1,
|
||||
'trailing_pe' => 30.34,
|
||||
'market_cap' => 9800700600,
|
||||
'book_value' => 4.7,
|
||||
'last_dividend_date' => now()->subDays(45),
|
||||
'dividend_yield' => (float) 0.033
|
||||
'dividend_yield' => 0.033
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -35,21 +39,21 @@ class FakeMarketData implements MarketDataInterface
|
||||
{
|
||||
|
||||
return collect([
|
||||
[
|
||||
new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => now()->subMonths(3)->format('Y-m-d H:i:s'),
|
||||
'date' => now()->subMonths(3),
|
||||
'dividend_amount' => 2.11,
|
||||
],
|
||||
[
|
||||
]),
|
||||
new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => now()->subMonths(6)->format('Y-m-d H:i:s'),
|
||||
'date' => now()->subMonths(6),
|
||||
'dividend_amount' => 1.89,
|
||||
],
|
||||
[
|
||||
]),
|
||||
new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => now()->subMonths(9)->format('Y-m-d H:i:s'),
|
||||
'date' => now()->subMonths(9),
|
||||
'dividend_amount' => 0.95,
|
||||
],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -57,11 +61,11 @@ class FakeMarketData implements MarketDataInterface
|
||||
{
|
||||
|
||||
return collect([
|
||||
[
|
||||
new Split([
|
||||
'symbol' => $symbol,
|
||||
'date' => now()->subMonths(36)->format('Y-m-d H:i:s'),
|
||||
'date' => now()->subMonths(36),
|
||||
'split_amount' => 10,
|
||||
],
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -73,11 +77,11 @@ class FakeMarketData implements MarketDataInterface
|
||||
|
||||
$date = now()->subDays($i)->format('Y-m-d');
|
||||
|
||||
$series[$date] = [
|
||||
$series[$date] = new Ohlc([
|
||||
'symbol' => $symbol,
|
||||
'date' => $date,
|
||||
'close' => (float) rand(150, 400),
|
||||
];
|
||||
'close' => rand(150, 400),
|
||||
]);
|
||||
}
|
||||
|
||||
return collect($series);
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace App\Interfaces\MarketData;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Interfaces\MarketData\Types\Ohlc;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
use App\Interfaces\MarketData\Types\Split;
|
||||
use App\Interfaces\MarketData\Types\Dividend;
|
||||
|
||||
class FinnhubMarketData implements MarketDataInterface
|
||||
{
|
||||
@@ -24,12 +28,12 @@ class FinnhubMarketData implements MarketDataInterface
|
||||
return $this->quote($symbol)->isNotEmpty();
|
||||
}
|
||||
|
||||
public function quote($symbol): Collection
|
||||
public function quote(string $symbol): Quote
|
||||
{
|
||||
|
||||
|
||||
$quote = $this->client->quote($symbol);
|
||||
|
||||
if (empty($quote)) return new Quote();
|
||||
|
||||
$fundamental = cache()->remember(
|
||||
'fh-symbol-'.$symbol,
|
||||
1440,
|
||||
@@ -38,20 +42,18 @@ class FinnhubMarketData implements MarketDataInterface
|
||||
}
|
||||
);
|
||||
|
||||
if (empty($fundamental)) return collect();
|
||||
|
||||
return collect([
|
||||
return new Quote([
|
||||
'name' => Arr::get($fundamental, 'metric.name'),
|
||||
'symbol' => $symbol,
|
||||
'market_value' => (float) Arr::get($quote, 'c'),
|
||||
'fifty_two_week_high' => (float) Arr::get($fundamental, 'metric.52WeekHigh'),
|
||||
'fifty_two_week_low' => (float) Arr::get($fundamental, 'metric.52WeekLow'),
|
||||
'forward_pe' => (float) Arr::get($fundamental, 'metric.forwardPE'), // confirm
|
||||
'trailing_pe' => (float) Arr::get($fundamental, 'metric.trailingPE'), // confirm
|
||||
'market_cap' => (int) Arr::get($fundamental, 'metric.marketCapitalization'), // confirm
|
||||
'book_value' => (float) Arr::get($fundamental, 'metric.bookValuePerShare'), // confirm
|
||||
'market_value' => Arr::get($quote, 'c'),
|
||||
'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
|
||||
'last_dividend_date' => Arr::get($fundamental, 'metric.lastDivDate'), // confirm
|
||||
'dividend_yield' => (float) Arr::get($fundamental, 'metric.dividendYield'), // confirm
|
||||
'dividend_yield' => Arr::get($fundamental, 'metric.dividendYield'), // confirm
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -61,12 +63,11 @@ class FinnhubMarketData implements MarketDataInterface
|
||||
|
||||
return collect($dividends)->map(function($dividend) use ($symbol) {
|
||||
|
||||
return [
|
||||
return new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => Carbon::parse(Arr::get($dividend, 'date'))
|
||||
->format('Y-m-d H:i:s'),
|
||||
'date' => Carbon::parse(Arr::get($dividend, 'date')),
|
||||
'dividend_amount' => Arr::get($dividend, 'amount'),
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,12 +78,11 @@ class FinnhubMarketData implements MarketDataInterface
|
||||
|
||||
return collect($splits)->map(function($split) use ($symbol) {
|
||||
|
||||
return [
|
||||
return new Split([
|
||||
'symbol' => $symbol,
|
||||
'date' => Carbon::parse(Arr::get($split, 'date'))
|
||||
->format('Y-m-d H:i:s'),
|
||||
'date' => Carbon::parse(Arr::get($split, 'date')),
|
||||
'split_amount' => Arr::get($split, 'toFactor') / Arr::get($split, 'fromFactor'),
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,11 +96,11 @@ class FinnhubMarketData implements MarketDataInterface
|
||||
|
||||
return collect($timestamps)->mapWithKeys(function ($timestamp, $index) use ($symbol, $closes) {
|
||||
$date = Carbon::createFromTimestamp($timestamp)->format('Y-m-d');
|
||||
return [ $date => [
|
||||
return [ $date => new Ohlc([
|
||||
'symbol' => $symbol,
|
||||
'date' => $date,
|
||||
'close' => (float) $closes[$index],
|
||||
]];
|
||||
'close' => $closes[$index],
|
||||
]) ];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Interfaces\MarketData;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
|
||||
interface MarketDataInterface
|
||||
{
|
||||
@@ -20,9 +21,9 @@ interface MarketDataInterface
|
||||
*
|
||||
* @param String $symbol
|
||||
*
|
||||
* @return Collection
|
||||
* @return Quote
|
||||
*/
|
||||
public function quote(String $symbol): Collection;
|
||||
public function quote(String $symbol): Quote;
|
||||
|
||||
/**
|
||||
* Get dividend data
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces\MarketData\Types;
|
||||
|
||||
use DateTime;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Interfaces\MarketData\Types\MarketDataType;
|
||||
|
||||
class Dividend extends MarketDataType
|
||||
{
|
||||
public function setSymbol(string $symbol): self
|
||||
{
|
||||
$this->items['symbol'] = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->items['symbol'] ?? '';
|
||||
}
|
||||
|
||||
public function setDividendAmount($dividendAmount): self
|
||||
{
|
||||
$this->items['dividend_amount'] = (float) $dividendAmount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDividendAmount(): float
|
||||
{
|
||||
return $this->items['dividend_amount'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setDate(String|DateTime $date): self
|
||||
{
|
||||
$this->items['date'] = Carbon::parse($date)->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDate(): ?DateTime
|
||||
{
|
||||
return $this->items['date'] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces\MarketData\Types;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class MarketDataType extends Collection
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct($items = [])
|
||||
{
|
||||
|
||||
foreach($this->getArrayableItems($items) as $key => $value) {
|
||||
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$this->{'set'.Str::studly($key)}($value);
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
return $this->items[$key] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces\MarketData\Types;
|
||||
|
||||
use DateTime;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Interfaces\MarketData\Types\MarketDataType;
|
||||
|
||||
class Ohlc extends MarketDataType
|
||||
{
|
||||
public function setSymbol(string $symbol): self
|
||||
{
|
||||
$this->items['symbol'] = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->items['symbol'] ?? '';
|
||||
}
|
||||
|
||||
public function setOpen($open): self
|
||||
{
|
||||
$this->items['open'] = (float) $open;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOpen(): float
|
||||
{
|
||||
return $this->items['open'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setHigh($high): self
|
||||
{
|
||||
$this->items['high'] = (float) $high;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHigh(): float
|
||||
{
|
||||
return $this->items['high'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setLow($low): self
|
||||
{
|
||||
$this->items['low'] = (float) $low;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLow(): float
|
||||
{
|
||||
return $this->items['low'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setClose($close): self
|
||||
{
|
||||
$this->items['close'] = (float) $close;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClose(): float
|
||||
{
|
||||
return $this->items['close'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setDate(String|DateTime $date): self
|
||||
{
|
||||
$this->items['date'] = Carbon::parse($date)->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDate(): ?DateTime
|
||||
{
|
||||
return $this->items['date'] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces\MarketData\Types;
|
||||
|
||||
use DateTime;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Interfaces\MarketData\Types\MarketDataType;
|
||||
|
||||
class Quote extends MarketDataType
|
||||
{
|
||||
public function setName($name): self
|
||||
{
|
||||
$this->items['name'] = (string) $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->items['name'] ?? '';
|
||||
}
|
||||
|
||||
public function setSymbol($symbol): self
|
||||
{
|
||||
$this->items['symbol'] = (string) $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->items['symbol'] ?? '';
|
||||
}
|
||||
|
||||
public function setMarketValue($marketValue): self
|
||||
{
|
||||
$this->items['market_value'] = (float) $marketValue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMarketValue(): float
|
||||
{
|
||||
return $this->items['market_value'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setFiftyTwoWeekHigh($high): self
|
||||
{
|
||||
$this->items['fifty_two_week_high'] = (float) $high;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFiftyTwoWeekHigh(): float
|
||||
{
|
||||
return $this->items['fifty_two_week_high'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setFiftyTwoWeekLow($low): self
|
||||
{
|
||||
$this->items['fifty_two_week_low'] = (float) $low;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFiftyTwoWeekLow(): float
|
||||
{
|
||||
return $this->items['fifty_two_week_low'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setForwardPE($pe): self
|
||||
{
|
||||
$this->items['forward_pe'] = (float) $pe;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getForwardPE(): float
|
||||
{
|
||||
return $this->items['forward_pe'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setTrailingPE($pe): self
|
||||
{
|
||||
$this->items['trailing_pe'] = (float) $pe;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTrailingPE(): float
|
||||
{
|
||||
return $this->items['trailing_pe'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setMarketCap($cap): self
|
||||
{
|
||||
$this->items['market_cap'] = (int) $cap;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMarketCap(): int
|
||||
{
|
||||
return $this->items['market_cap'] ?? 0;
|
||||
}
|
||||
|
||||
public function setBookValue($value): self
|
||||
{
|
||||
$this->items['book_value'] = (float) $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBookValue(): float
|
||||
{
|
||||
return $this->items['book_value'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setLastDividendDate(mixed $date): self
|
||||
{
|
||||
$this->items['last_dividend_date'] = is_null($date) ? null : Carbon::parse($date)->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLastDividendDate(): ?DateTime
|
||||
{
|
||||
return $this->items['last_dividend_date'] ?? null;
|
||||
}
|
||||
|
||||
public function setDividendYield($yield): self
|
||||
{
|
||||
$this->items['dividend_yield'] = (float) $yield;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDividendYield(): float
|
||||
{
|
||||
return $this->items['dividend_yield'] ?? 0.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces\MarketData\Types;
|
||||
|
||||
use DateTime;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Interfaces\MarketData\Types\MarketDataType;
|
||||
|
||||
class Split extends MarketDataType
|
||||
{
|
||||
public function setSymbol(string $symbol): self
|
||||
{
|
||||
$this->items['symbol'] = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->items['symbol'] ?? '';
|
||||
}
|
||||
|
||||
public function setSplitAmount($splitAmount): self
|
||||
{
|
||||
$this->items['split_amount'] = (float) $splitAmount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSplitAmount(): float
|
||||
{
|
||||
return $this->items['split_amount'] ?? 0.0;
|
||||
}
|
||||
|
||||
public function setDate(String|DateTime $date): self
|
||||
{
|
||||
$this->items['date'] = Carbon::parse($date)->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDate(): ?DateTime
|
||||
{
|
||||
return $this->items['date'] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,10 @@ namespace App\Interfaces\MarketData;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Scheb\YahooFinanceApi\ApiClient;
|
||||
use App\Interfaces\MarketData\Types\Ohlc;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
use App\Interfaces\MarketData\Types\Split;
|
||||
use App\Interfaces\MarketData\Types\Dividend;
|
||||
use Scheb\YahooFinanceApi\ApiClientFactory as YahooFinance;
|
||||
|
||||
class YahooMarketData implements MarketDataInterface
|
||||
@@ -22,25 +26,25 @@ class YahooMarketData implements MarketDataInterface
|
||||
return $this->quote($symbol)->isNotEmpty();
|
||||
}
|
||||
|
||||
public function quote(String $symbol): Collection
|
||||
public function quote(String $symbol): Quote
|
||||
{
|
||||
|
||||
$quote = $this->client->getQuote($symbol);
|
||||
|
||||
if (empty($quote)) return collect();
|
||||
|
||||
return collect([
|
||||
return new Quote([
|
||||
'name' => $quote->getLongName() ?? $quote->getShortName(),
|
||||
'symbol' => $quote->getSymbol(),
|
||||
'market_value' => (float) $quote->getRegularMarketPrice(),
|
||||
'fifty_two_week_high' => (float) $quote->getFiftyTwoWeekHigh(),
|
||||
'fifty_two_week_low' => (float) $quote->getFiftyTwoWeekLow(),
|
||||
'forward_pe' => (float) $quote->getForwardPE(),
|
||||
'trailing_pe' => (float) $quote->getTrailingPE(),
|
||||
'market_cap' => (int) $quote->getMarketCap(),
|
||||
'book_value' => (float) $quote->getBookValue(),
|
||||
'market_value' => $quote->getRegularMarketPrice(),
|
||||
'fifty_two_week_high' => $quote->getFiftyTwoWeekHigh(),
|
||||
'fifty_two_week_low' => $quote->getFiftyTwoWeekLow(),
|
||||
'forward_pe' => $quote->getForwardPE(),
|
||||
'trailing_pe' => $quote->getTrailingPE(),
|
||||
'market_cap' => $quote->getMarketCap(),
|
||||
'book_value' => $quote->getBookValue(),
|
||||
'last_dividend_date' => $quote->getDividendDate(),
|
||||
'dividend_yield' => (float) $quote->getTrailingAnnualDividendYield() * 100
|
||||
'dividend_yield' => $quote->getTrailingAnnualDividendYield() * 100
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -50,11 +54,11 @@ class YahooMarketData implements MarketDataInterface
|
||||
return collect($this->client->getHistoricalDividendData($symbol, $startDate, $endDate))
|
||||
->map(function($dividend) use ($symbol) {
|
||||
|
||||
return [
|
||||
return new Dividend([
|
||||
'symbol' => $symbol,
|
||||
'date' => $dividend->getDate()->format('Y-m-d H:i:s'),
|
||||
'date' => $dividend->getDate(),
|
||||
'dividend_amount' => $dividend->getDividends(),
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,11 +69,11 @@ class YahooMarketData implements MarketDataInterface
|
||||
->map(function($split) use ($symbol) {
|
||||
$split_amount = explode(':', $split->getStockSplits());
|
||||
|
||||
return [
|
||||
return new Split([
|
||||
'symbol' => $symbol,
|
||||
'date' => $split->getDate()->format('Y-m-d H:i:s'),
|
||||
'date' => $split->getDate(),
|
||||
'split_amount' => $split_amount[0] / $split_amount[1],
|
||||
];
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,11 +85,11 @@ class YahooMarketData implements MarketDataInterface
|
||||
|
||||
$date = $history->getDate()->format('Y-m-d');
|
||||
|
||||
return [ $date => [
|
||||
return [ $date => new Ohlc([
|
||||
'symbol' => $symbol,
|
||||
'date' => $date,
|
||||
'close' => (float) $history->getClose(),
|
||||
]];
|
||||
'close' => $history->getClose(),
|
||||
]) ];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Log;
|
||||
use App\Interfaces\MarketData\YahooMarketData;
|
||||
use App\Interfaces\MarketData\FallbackInterface;
|
||||
use App\Interfaces\MarketData\AlphaVantageMarketData;
|
||||
use App\Interfaces\MarketData\Types\Quote;
|
||||
|
||||
class FallbackInterfaceTest extends TestCase
|
||||
{
|
||||
@@ -32,7 +33,7 @@ class FallbackInterfaceTest extends TestCase
|
||||
|
||||
$alphaMock = Mockery::mock(AlphaVantageMarketData::class);
|
||||
$alphaMock->shouldReceive('quote')
|
||||
->andReturn(collect(['Alpha data']));
|
||||
->andReturn(new Quote(['market_value' => 10]));
|
||||
|
||||
$this->app->instance(YahooMarketData::class, $yahooMock);
|
||||
$this->app->instance(AlphaVantageMarketData::class, $alphaMock);
|
||||
@@ -41,7 +42,7 @@ class FallbackInterfaceTest extends TestCase
|
||||
|
||||
$result = $fallbackInterface->quote('ACME');
|
||||
|
||||
$this->assertEquals(collect(['Alpha data']), $result);
|
||||
$this->assertEquals(new Quote(['market_value' => 10]), $result);
|
||||
|
||||
Log::shouldHaveReceived('warning')->with('Failed calling method quote (yahoo): Yahoo failed');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user