LastPlaying

SET Stock Sell UPPER Limit [[(I)nfo]]]
"File not found: $filename"]; } $content = file_get_contents($filename); if ($content === false) { return ['error' => "Could not read file: $filename"]; } return ['content' => $content]; } // --- Get current price by symbol using CHART endpoint --- function getCurrentPrice($symbol) { $url = "https://query1.finance.yahoo.com/v8/finance/chart/" . urlencode($symbol); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, 20); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); $response = curl_exec($ch); curl_close($ch); if (!$response) { return null; } $data = json_decode($response, true); if (isset($data['chart']['result'][0]['meta']['regularMarketPrice'])) { return [ 'price' => (float)$data['chart']['result'][0]['meta']['regularMarketPrice'], 'symbol' => $data['chart']['result'][0]['meta']['symbol'], 'currency' => $data['chart']['result'][0]['meta']['currency'] ?? 'USD' ]; } return null; } // --- Clean symbol (remove .F, .DE, .XE, .TO, .L, etc.) --- function cleanSymbol($symbol) { $dotPos = strpos($symbol, '.'); if ($dotPos !== false) { return substr($symbol, 0, $dotPos); } return $symbol; } // --- Get price with fallback: Try original FIRST, then cleaned --- function getPriceWithFallback($originalSymbol) { // Step 1: Try original symbol as-is (with .TO, .L, .AX, etc.) $quote = getCurrentPrice($originalSymbol); if ($quote) { return $quote; } // Step 2: If original fails, try cleaned symbol (remove suffix) $cleanedSymbol = cleanSymbol($originalSymbol); if ($cleanedSymbol !== $originalSymbol) { $quote = getCurrentPrice($cleanedSymbol); if ($quote) { return $quote; } } return null; } // --- Read local stocks.json --- echo "Reading stocks.json from local directory...\n"; $result = readLocalJson($stocksJsonFile); if (isset($result['error'])) { die("Error: " . $result['error'] . "\n"); } $stocks = json_decode($result['content'], true); if (!$stocks) { die("Invalid JSON in stocks.json\n"); } // Filter: ONLY stocks with ISIN AND nrbght $stocksWithIsin = array_filter($stocks, function($s) { return isset($s['isin']) && !empty($s['isin']) && isset($s['nrbght']) && $s['nrbght'] > 0; }); echo "Found " . count($stocksWithIsin) . " stocks with ISIN and share counts\n"; // Process each stock $risen = []; $fallen = []; $same = []; $errors = []; $totalInvested = 0; $totalCurrentValue = 0; $totalWinsSum = 0; // NEW: Sum of all winning gains $totalLossesSum = 0; // NEW: Sum of all losing losses (absolute value for display) foreach ($stocksWithIsin as $stock) { $name = $stock['stock']; // Keep original with suffix! $isin = $stock['isin']; $oldPrice = (float)$stock['price']; $shares = (int)$stock['nrbght']; $depot = $stock['depot'] ?? 'unknown'; // Calculate invested amount $invested = $oldPrice * $shares; $totalInvested += $invested; // Get price with fallback: try original FIRST, then cleaned $quote = getPriceWithFallback($name); if (!$quote) { $errors[] = [ 'name' => $name, 'original_symbol' => $name, 'isin' => $isin, 'shares' => $shares, 'old' => $oldPrice, 'invested' => $invested, 'depot' => $depot, 'error' => 'Could not fetch price' ]; continue; } $currentPrice = $quote['price']; $usedSymbol = $quote['symbol']; // This might be cleaned version // Calculate position values $currentTotal = $currentPrice * $shares; $totalChange = $currentTotal - $invested; $changePerShare = $currentPrice - $oldPrice; $percentChange = ($changePerShare / $oldPrice) * 100; $totalCurrentValue += $currentTotal; // NEW: Add to totals for wins/losses if ($totalChange > 0) { $totalWinsSum += $totalChange; } elseif ($totalChange < 0) { $totalLossesSum += abs($totalChange); // Store as positive number for display } $result = [ 'name' => $name, 'original_symbol' => $name, // Store original for iframe! 'lookup_symbol' => $usedSymbol, // What Yahoo actually used 'isin' => $isin, 'shares' => $shares, 'old' => $oldPrice, 'current' => $currentPrice, 'invested' => $invested, 'currentTotal' => $currentTotal, 'totalChange' => $totalChange, 'changePerShare' => $changePerShare, 'percent' => $percentChange, 'depot' => $depot ]; if ($currentPrice > $oldPrice) { $risen[] = $result; } elseif ($currentPrice < $oldPrice) { $fallen[] = $result; } else { $same[] = $result; } } $totalGainLoss = $totalCurrentValue - $totalInvested; $totalReturnPercent = ($totalInvested > 0) ? ($totalGainLoss / $totalInvested) * 100 : 0; // --- Output HTML --- header('Content-Type: text/html; charset=utf-8'); ?> Portfolio Performance - Individual Position Gains

📊 Portfolio Performance

Stocks with ISIN codes | Local file: stocks.json | Lookup: Try original symbol first, then cleaned (remove suffix)
$
Total Invested
= 0 ? '+' : '' ?>$
Total = 0 ? 'Gain' : 'Loss' ?>
$
Current Value
= 0 ? '+' : '' ?>%
Total Return

📈 Winning Positions (Price Increased) 🏆 Total Gains: +$

Stock / Symbol ISIN Depot Shares × Buy Price Current Gain/Share = Total Gain Return % Rating

× $ $ +$ = +$ +%
📉 Show Losing Positions ( items) 💸 Total Losses: -$

📉 Losing Positions (Price Decreased)

Stock / Symbol ISIN Depot Shares × Buy Price Current Loss/Share = Total Loss Return % Rating

× $ $ -$ = -$ %
âš ī¸ Show Lookup Errors ( items)

âš ī¸ Lookup Errors

StockISINDepotSharesInvestedErrorRating
$ —
TOTAL PORTFOLIO (Sum of all: Shares × Gain/Loss per share) = 0 ? '+' : '' ?>$ = 0 ? '+' : '' ?>%
BREAKDOWN: $ invested $ current