mirror of
https://github.com/henry4682/finance_app.git
synced 2026-07-16 08:20:00 +00:00
All checks were successful
Laravel-Oracle-Deploy / redeploy (push) Successful in 6s
149 lines
6.3 KiB
PHP
149 lines
6.3 KiB
PHP
<?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;
|
||
|
||
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']) ? substr($headerInfo['navDate'], 0, 10) : now()->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);
|
||
}
|
||
}
|
||
}
|