2024-08-10 13:30:19 -05:00
< ? php
namespace App\Models ;
use Illuminate\Database\Eloquent\Model ;
2024-08-30 21:58:38 -05:00
use App\Interfaces\MarketData\MarketDataInterface ;
2024-08-17 18:40:50 -05:00
use Illuminate\Database\Eloquent\Concerns\HasUuids ;
2024-08-10 13:30:19 -05:00
use Illuminate\Database\Eloquent\Factories\HasFactory ;
class Dividend extends Model
{
use HasFactory ;
2024-08-17 18:40:50 -05:00
use HasUuids ;
2024-08-10 13:30:19 -05:00
protected $fillable = [
'symbol' ,
'date' ,
'dividend_amount' ,
];
protected $hidden = [];
protected $casts = [
'date' => 'datetime' ,
'first_date' => 'datetime' ,
'last_date' => 'datetime' ,
];
/**
2024-08-30 21:58:38 -05:00
* Grab new dividend data
2024-08-10 13:30:19 -05:00
*
2024-08-30 21:58:38 -05:00
* @param string $symbol
2024-08-10 13:30:19 -05:00
* @return void
*/
2024-08-30 21:58:38 -05:00
public static function refreshDividendData ( string $symbol )
2024-08-10 13:30:19 -05:00
{
2024-08-30 21:58:38 -05:00
$dividends_meta = self :: where ([ 'symbol' => $symbol ])
-> selectRaw ( 'COUNT(symbol) as total_dividends' )
-> selectRaw ( 'MAX(date) as last_date' )
-> get ()
-> first ();
// assume we need to populate ALL dividend data
$start_date = new \DateTime ( '@0' );
$end_date = now ();
// nope, refresh forward looking only
if ( $dividends_meta -> total_dividends ) {
$start_date = $dividends_meta -> last_date -> addHours ( 48 );
$end_date = now ();
2024-08-10 13:30:19 -05:00
}
2024-08-30 21:58:38 -05:00
// get some data
if ( $dividend_data = collect () && $start_date && $end_date ) {
$dividend_data = app ( MarketDataInterface :: class ) -> dividends ( $symbol , $start_date , $end_date );
}
// ah, we found some dividends...
if ( $dividend_data -> isNotEmpty ()) {
// create mass insert
foreach ( $dividend_data as $index => $dividend ){
$dividend_data [ $index ] = [ ... $dividend , ... [ 'updated_at' => now (), 'created_at' => now ()]];
}
// insert records
( new self ) -> insert ( $dividend_data -> toArray ());
// sync to holdings
$dividends = self :: where ([
'dividends.symbol' => $dividend_data -> last () -> symbol ,
]) -> select ([ 'holdings.portfolio_id' , 'dividends.date' , 'dividends.symbol' , 'dividends.dividend_amount' ])
-> selectRaw ( '@purchased:=(SELECT coalesce(SUM(quantity),0) FROM transactions WHERE transactions.transaction_type = "BUY" AND transactions.symbol = dividends.symbol AND date(transactions.date) <= date(dividends.date) AND holdings.portfolio_id = transactions.portfolio_id ) AS `purchased`' )
-> selectRaw ( '@sold:=(SELECT coalesce(SUM(quantity),0) FROM transactions WHERE transactions.transaction_type = "SELL" AND transactions.symbol = dividends.symbol AND date(transactions.date) <= date(dividends.date) AND holdings.portfolio_id = transactions.portfolio_id ) AS `sold`' )
-> selectRaw ( '@owned:=(@purchased - @sold) AS `owned`' )
-> selectRaw ( '@dividends_received:=(@owned * dividends.dividend_amount) AS `dividends_received`' )
-> join ( 'transactions' , 'transactions.symbol' , 'dividends.symbol' )
-> join ( 'holdings' , 'transactions.portfolio_id' , 'holdings.portfolio_id' )
-> groupBy ([ 'holdings.portfolio_id' , 'dividends.date' , 'dividends.symbol' , 'dividends.dividend_amount' ])
-> get ();
// iterate through holdings and update
Holding :: where ([ 'symbol' => $symbol ])
-> get ()
-> each ( function ( $holding ) use ( $dividends ) {
$holding -> update ([
'dividends_earned' => $dividends -> where ( 'portfolio_id' , $holding -> portfolio_id ) -> sum ( 'dividends_received' )
]);
});
// sync most last dividend date in market data
$market_data = MarketData :: symbol ( $symbol ) -> first ();
$dividend_data_latest_date = $dividend_data -> sortByDesc ( 'date' ) -> first ()[ 'date' ];
if ( $market_data -> dividend_date < $dividend_data_latest_date ) {
$market_data -> update ([ 'dividend_date' => $dividend_data_latest_date ]); // why is this set to latest date?
}
}
return $dividend_data ;
2024-08-10 13:30:19 -05:00
}
public function marketData () {
return $this -> belongsTo ( MarketData :: class , 'symbol' , 'symbol' );
}
public function holdings () {
return $this -> hasMany ( Holding :: class , 'symbol' , 'symbol' );
}
public function transactions () {
return $this -> hasMany ( Transaction :: class , 'symbol' , 'symbol' );
}
}