Files
finance_app/app/Jobs/UpdateAssetPriceJob.php
henry yo 1d9ae792fa
All checks were successful
Laravel-Oracle-Deploy / redeploy (push) Successful in 1m10s
fix: add md & fix dateformat & add note
2026-07-03 02:00:01 +08:00

152 lines
6.7 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Jobs;
use App\Models\Security;
use App\Models\SecurityPriceHistories;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class UpdateAssetPriceJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $symbol;
protected $type;
protected $defaultName;
public function __construct(string $symbol, string $type, string $defaultName)
{
$this->symbol = $symbol;
$this->type = $type;
$this->defaultName = $defaultName;
}
public function handle(): void
{
try {
Log::info("🔄 開始從持倉清單發動爬蟲: [{$this->symbol}] {$this->defaultName}");
$isRealPrice = true;
$latestPrice = 0;
$latestPriceDate = null;
$name = $this->defaultName;
$changeAmount = 0;
$changeRate = 0;
$error = null;
// 股票去爬證交所
if ($this->type === 'stock') {
Log::info("開始抓取{$this->type}:{$this->symbol}價格");
$response = Http::timeout(10)->get("https://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch=tse_{$this->symbol}.tw");
if ($response->successful()) {
$json = $response->json();
$info = $json['msgArray'][0] ?? null;
if (isset($info['^']) && !Carbon::parse($info['^'])->isToday()) {
$isRealPrice = false;
}
if ($info) {
$latestPrice = floatval($info['z'] ?? $info['o'] ?? 0);
$latestPriceDate = isset($info['d']) ? Carbon::parse($info['d'])->format('Y-m-d') : now()->format('Y-m-d');
$name = $info['n'] ?? $this->defaultName;
// 忘了備份時用的
// $latestPriceDate = isset($info['d']) ? Carbon::parse($info['d'], 'Asia/Taipei')->subDay()->format('Y-m-d') : now()->subDay()->format('Y-m-d');
if (isset($info['y']) && $latestPrice > 0) {
$changeAmount = floatval($latestPrice - $info['y']);
$changeRate = ($changeAmount / $info['y']) * 100;
}
}
}
} elseif ($this->type === 'fund') {
Log::info("開始抓取{$this->type}:{$this->symbol}價格");
// 去鉅亨網抓
$response = Http::timeout(10)
->withHeaders([
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer' => 'https://www.anuefund.com/',
'Accept' => 'application/json, text/plain, */*',
])
->get("https://www.anuefund.com/anuefundApi/FundDetail/FundInfo", [
'fundDetailEnum' => 'FundINFO',
'FundID' => $this->symbol
]);
if ($response->successful()) {
$json = $response->json();
$headerInfo = $json['data']['hearder'] ?? null;
if (isset($headerInfo['navDate']) && !Carbon::parse($headerInfo['navDate'])->isToday()) {
//不是當天資料不更新
$isRealPrice = false;
}
if ($headerInfo) {
$latestPriceDate = isset($headerInfo['navDate']) ? Carbon::parse($headerInfo['navDate'], 'Asia/Taipei')->format('Y-m-d') : now()->format('Y-m-d');
// 忘了備份時用的
// $latestPriceDate = isset($headerInfo['navDate']) ? Carbon::parse($headerInfo['navDate'], 'Asia/Taipei')->subDay()->format('Y-m-d') : now()->subDay()->format('Y-m-d');
$latestPrice = floatval($headerInfo['nav'] ?? 0);
if ($latestPriceDate !== now()->format('Y-m-d')) {
//不是當天資料不更新
$isRealPrice = false;
$latestPrice = 0;
}
$name = $headerInfo['fundName'] ?? $this->defaultName;
$changeAmount = floatval($headerInfo['upDown'] ?? 0);
$changeRate = floatval($headerInfo['upDownRate'] ?? 0);
}
}
Log::info("抓取{$this->type}:{$this->symbol}資料結束");
}
// 爬蟲成功拿到有效股價,幫新表補資料
if ($latestPrice > 0 && $isRealPrice) {
Log::info("開始寫入Security和SecurityPriceHistories表標的: [{$this->symbol}],價格: {$latestPrice}---");
$security = Security::updateOrCreate(
['code' => $this->symbol],
[
'type' => $this->type,
'name' => $name,
'latest_price' => $latestPrice,
'latest_price_at' => $latestPriceDate,
'change_amount' => $changeAmount,
'change_rate' => $changeRate,
'source' => 'twse',
]
);
SecurityPriceHistories::updateOrCreate(
[
'security_id' => $security->id,
'price_date' => $latestPriceDate, // 記錄今天的日期
],
[
'price' => $latestPrice,
'change_amount' => $changeAmount,
'change_rate' => $changeRate,
'created_at' => now(),
'updated_at' => now(),
]
);
Log::info("✅ Security & SecurityPriceHistories 標的 [{$this->symbol}] 補齊並更新成功: {$latestPrice}");
} elseif (!$isRealPrice) {
Log::info(" 標的 [{$this->symbol}] 抓到的價格是非即時的,不更新價格資訊。");
} else {
Log::warning("⚠️ 標的 [{$this->symbol}] 未能從證交所抓到有效價格,{$error}");
}
} catch (\Exception $e) {
Log::error("❌ 更新標的 [{$this->symbol}] 價格時發生異常: " . $e->getMessage());
$this->release(60);
}
}
}