diff --git a/app/Console/Commands/CaptureDailyChange.php b/app/Console/Commands/CaptureDailyChange.php index ad13f0f..c19fa53 100644 --- a/app/Console/Commands/CaptureDailyChange.php +++ b/app/Console/Commands/CaptureDailyChange.php @@ -53,7 +53,7 @@ class CaptureDailyChange extends Command return $holding->market_data->market_value * $holding->quantity; }); - $portfolio->daily_changes()->create([ + $portfolio->daily_change()->create([ 'date' => now(), 'total_market_value' => $total_market_value, 'total_cost_basis' => $total_cost_basis, diff --git a/app/Console/Commands/RefreshDividendData.php b/app/Console/Commands/RefreshDividendData.php index 40c25fd..8356fad 100644 --- a/app/Console/Commands/RefreshDividendData.php +++ b/app/Console/Commands/RefreshDividendData.php @@ -39,8 +39,7 @@ class RefreshDividendData extends Command */ public function handle() { - // $holdings = Holding::where('quantity', '>', 0)->distinct()->get(['symbol']); - $holdings = Holding::distinct()->get(['symbol']); + $holdings = Holding::where('quantity', '>', 0)->distinct()->get(['symbol']); foreach ($holdings as $holding) { $this->line('Refreshing ' . $holding->symbol); diff --git a/app/Console/Commands/RefreshMarketData.php b/app/Console/Commands/RefreshMarketData.php index bb7d0a1..23383ee 100644 --- a/app/Console/Commands/RefreshMarketData.php +++ b/app/Console/Commands/RefreshMarketData.php @@ -41,16 +41,15 @@ class RefreshMarketData extends Command public function handle() { // get all symbols from market data - $symbols = Holding::where('quantity', '>', 0) + $holdings = Holding::where('quantity', '>', 0) ->select(['symbol']) ->distinct() - ->get() - ->pluck('symbol'); + ->get(); - foreach ($symbols as $symbol) { - $this->line('Refreshing ' . $symbol); + foreach ($holdings as $holding) { + $this->line('Refreshing ' . $holding->symbol); - MarketData::getMarketData($symbol); + MarketData::getMarketData($holding->symbol); } } } diff --git a/app/Console/Commands/RefreshSplitData.php b/app/Console/Commands/RefreshSplitData.php index bb504c9..6623d00 100644 --- a/app/Console/Commands/RefreshSplitData.php +++ b/app/Console/Commands/RefreshSplitData.php @@ -40,7 +40,7 @@ class RefreshSplitData extends Command */ public function handle() { - $holdings = Holding::distinct()->get(['symbol']); + $holdings = Holding::where('quantity', '>', 0)->distinct()->get(['symbol']); foreach ($holdings as $holding) { $this->line('Refreshing ' . $holding->symbol); diff --git a/app/Console/Commands/SyncHoldingData.php b/app/Console/Commands/SyncHoldingData.php index 3174278..cf2ac28 100644 --- a/app/Console/Commands/SyncHoldingData.php +++ b/app/Console/Commands/SyncHoldingData.php @@ -12,14 +12,14 @@ class SyncHoldingData extends Command * * @var string */ - protected $signature = 'holding-data:refresh'; + protected $signature = 'holding-data:sync'; /** * The console command description. * * @var string */ - protected $description = 'Refresh holdings'; + protected $description = 'Syncs holdings with transactions and dividends'; /** * Create a new command instance. diff --git a/app/Http/Controllers/PortfolioController.php b/app/Http/Controllers/PortfolioController.php index 91e41fb..3564f4e 100644 --- a/app/Http/Controllers/PortfolioController.php +++ b/app/Http/Controllers/PortfolioController.php @@ -25,7 +25,7 @@ class PortfolioController extends Controller $portfolio->load(['transactions', 'holdings']); // get portfolio metrics - $metrics = cache()->tags(['metrics', 'portfolio', auth()->user()->id, $portfolio->id])->remember( + $metrics = cache()->tags(['metrics', 'portfolio', $portfolio->id])->remember( 'portfolio-metrics-' . $portfolio->id, 60, function () use ($portfolio) { diff --git a/app/Models/Dividend.php b/app/Models/Dividend.php index 76fc17a..0b55ec4 100644 --- a/app/Models/Dividend.php +++ b/app/Models/Dividend.php @@ -22,7 +22,6 @@ class Dividend extends Model protected $casts = [ 'date' => 'datetime', - 'first_date' => 'datetime', 'last_date' => 'datetime', ]; diff --git a/app/Models/Holding.php b/app/Models/Holding.php index 9a7c0f5..0702fed 100644 --- a/app/Models/Holding.php +++ b/app/Models/Holding.php @@ -25,12 +25,10 @@ class Holding extends Model 'realized_gain_dollars', 'dividends_earned', 'splits_synced_at', - 'dividends_synced_at' ]; protected $casts = [ 'splits_synced_at' => 'datetime', - 'dividends_synced_at' => 'datetime', ]; protected $attributes = [ diff --git a/app/Models/Split.php b/app/Models/Split.php index 4e1d70c..27f64d4 100644 --- a/app/Models/Split.php +++ b/app/Models/Split.php @@ -24,7 +24,6 @@ class Split extends Model protected $casts = [ 'date' => 'datetime', - 'first_date' => 'datetime', 'last_date' => 'datetime', ]; @@ -48,7 +47,6 @@ class Split extends Model // dates for split data $splits_meta = self::where(['symbol' => $symbol]) ->selectRaw('COUNT(symbol) as total_splits') - ->selectRaw('MIN(date) as first_date') ->selectRaw('MAX(date) as last_date') ->get() ->first(); @@ -76,8 +74,6 @@ class Split extends Model // sync to transactions self::syncToTransactions($symbol); - - return $split_data; } /** @@ -92,7 +88,7 @@ class Split extends Model $splits = self::where([ 'splits.symbol' => $symbol, ]) - ->whereDate('transactions.date', '>', DB::raw('IFNULL(market_data.splits_synced_to_holdings_at, "0000-00-00")')) + ->whereDate('transactions.date', '>', DB::raw('IFNULL(holdings.splits_synced_at, "0000-00-00")')) ->select([ 'splits.date', 'splits.symbol', @@ -100,7 +96,7 @@ class Split extends Model 'transactions.portfolio_id' ]) ->join('transactions', 'transactions.symbol', 'splits.symbol') - ->join('market_data', 'transactions.symbol', 'market_data.symbol') + ->join('holdings', 'transactions.symbol', 'holdings.symbol') ->orderBy('splits.date', 'ASC') ->get(); @@ -126,11 +122,15 @@ class Split extends Model 'created_at' => now(), 'updated_at' => now() ]); + + Holding::where([ + 'symbol' => $split->symbol, + 'portfolio_id' => $split->portfolio_id + ])->update([ + 'splits_synced_at' => now() + ]); } } - - // // update market data with latest date - // MarketData::setSplitsHoldingSynced($symbol); } diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index dd1ef75..fa533d8 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -17,6 +17,7 @@ class Transaction extends Model protected $fillable = [ 'symbol', 'date', + 'portfolio_id', 'transaction_type', 'quantity', 'cost_basis', @@ -48,14 +49,14 @@ class Transaction extends Model $transaction->refreshMarketData(); - cache()->tags(['metrics', auth()->user()->id])->flush(); + cache()->tags(['metrics', $transaction->portfolio_id])->flush(); }); static::deleted(function ($transaction) { $transaction->syncToHolding(); - cache()->tags(['metrics', auth()->user()->id])->flush(); + cache()->tags(['metrics', $transaction->portfolio_id])->flush(); }); } diff --git a/database/migrations/2021_09_06_014744_create_holdings_table.php b/database/migrations/2021_09_06_014744_create_holdings_table.php index 3031330..c4a9692 100644 --- a/database/migrations/2021_09_06_014744_create_holdings_table.php +++ b/database/migrations/2021_09_06_014744_create_holdings_table.php @@ -25,7 +25,6 @@ class CreateHoldingsTable extends Migration $table->float('realized_gain_dollars', 12, 4)->nullable(); $table->float('dividends_earned', 12, 4)->nullable(); $table->timestamp('splits_synced_at')->nullable(); - $table->timestamp('dividends_synced_at')->nullable(); $table->timestamps(); }); } diff --git a/routes/console.php b/routes/console.php index 9634b2d..b44da19 100644 --- a/routes/console.php +++ b/routes/console.php @@ -1,14 +1,35 @@ weekdays()->everyMinute(); // configurable in 'config.market_data' +/** + * + * This scheduled job refreshes market data from your selected data provider + * Update the cadence with the MARKET_DATA_REFRESH key in your env file + */ +Schedule::command(RefreshMarketData::class)->weekdays()->everyMinute(); + +/** + * + * This scheduled job records daily changes to your portfolios every weekday + */ Schedule::command(CaptureDailyChange::class)->weekdays(); + +/** + * + * Refreshes dividend data for your holdings (and syncs new dividends to holdings) + */ Schedule::command(RefreshDividendData::class)->weekly(); + +/** + * + * Refreshes split data for your holdings (and creates new transactions for new splits) + */ Schedule::command(RefreshSplitData::class)->monthly(); + +/** + * + * Periodically reconciles your holdings with transactions and dividends + */ +Schedule::command(SyncHoldingData::class)->yearly();