boerse
All checks were successful
Deploy / deploy-staging (push) Successful in 6s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-22 01:31:18 +02:00
parent a1bab34bd3
commit 91dc84d027
16 changed files with 1697 additions and 86 deletions

View File

@@ -536,3 +536,148 @@ $mm->registerFunction($moduleName, 'alpha_vantage_search_symbols', static functi
'results' => $results,
];
});
$mm->registerFunction($moduleName, 'alpha_vantage_fetch_chart_series', static function (string $symbol): array {
$settings = modules()->settings('boersenchecker');
$apiKey = trim((string) ($settings['alpha_vantage_api_key'] ?? ''));
$timeout = (int) ($settings['alpha_vantage_timeout_sec'] ?? 12);
$timeout = $timeout > 0 ? $timeout : 12;
$symbol = strtoupper(trim($symbol));
if ($symbol === '') {
return ['ok' => false, 'message' => 'Kein Symbol angegeben.'];
}
if ($apiKey === '') {
return ['ok' => false, 'message' => 'Alpha-Vantage-API-Key fehlt.'];
}
$cacheDir = sys_get_temp_dir() . '/boersenchecker-alpha-vantage';
if (!is_dir($cacheDir)) {
@mkdir($cacheDir, 0775, true);
}
$fetchPayload = static function (string $functionName, int $ttl) use ($symbol, $apiKey, $timeout, $cacheDir): array {
$cacheKey = md5($functionName . '|' . $symbol . '|' . $apiKey);
$cachePath = $cacheDir . '/' . $cacheKey . '.json';
if (is_file($cachePath) && (time() - filemtime($cachePath)) < $ttl) {
$cached = file_get_contents($cachePath);
$decoded = is_string($cached) ? json_decode($cached, true) : null;
if (is_array($decoded)) {
return $decoded;
}
}
$url = 'https://www.alphavantage.co/query?' . http_build_query([
'function' => $functionName,
'symbol' => $symbol,
'apikey' => $apiKey,
'outputsize' => 'compact',
]);
$responseBody = null;
if (function_exists('curl_init')) {
$ch = curl_init($url);
if ($ch !== false) {
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => min(5, $timeout),
CURLOPT_HTTPHEADER => ['Accept: application/json'],
]);
$responseBody = curl_exec($ch);
curl_close($ch);
}
}
if (!is_string($responseBody) || $responseBody === '') {
$context = stream_context_create([
'http' => [
'method' => 'GET',
'timeout' => $timeout,
'header' => "Accept: application/json\r\n",
],
]);
$responseBody = @file_get_contents($url, false, $context);
}
$decoded = is_string($responseBody) ? json_decode($responseBody, true) : null;
if (is_array($decoded) && $decoded !== []) {
@file_put_contents($cachePath, json_encode($decoded, JSON_UNESCAPED_UNICODE));
return $decoded;
}
return [];
};
$normalizeSeries = static function (array $payload, array $keys): array {
foreach ($keys as $key) {
$series = $payload[$key] ?? null;
if (!is_array($series)) {
continue;
}
$points = [];
foreach ($series as $date => $row) {
if (!is_array($row)) {
continue;
}
$close = $row['4. close'] ?? $row['5. adjusted close'] ?? null;
if (!is_numeric($close)) {
$close = $row['5. adjusted close'] ?? $row['4. close'] ?? null;
}
if (!is_numeric($close)) {
continue;
}
$points[] = [
'date' => (string) $date,
'close' => (float) $close,
];
}
usort($points, static fn (array $left, array $right): int => strcmp((string) $left['date'], (string) $right['date']));
return $points;
}
return [];
};
$dailyPayload = $fetchPayload('TIME_SERIES_DAILY_ADJUSTED', 6 * 3600);
if (($dailyPayload['Information'] ?? null) || ($dailyPayload['Error Message'] ?? null)) {
$dailyPayload = $fetchPayload('TIME_SERIES_DAILY', 6 * 3600);
}
$weeklyPayload = $fetchPayload('TIME_SERIES_WEEKLY_ADJUSTED', 12 * 3600);
if (($weeklyPayload['Information'] ?? null) || ($weeklyPayload['Error Message'] ?? null)) {
$weeklyPayload = $fetchPayload('TIME_SERIES_WEEKLY', 12 * 3600);
}
$monthlyPayload = $fetchPayload('TIME_SERIES_MONTHLY_ADJUSTED', 24 * 3600);
if (($monthlyPayload['Information'] ?? null) || ($monthlyPayload['Error Message'] ?? null)) {
$monthlyPayload = $fetchPayload('TIME_SERIES_MONTHLY', 24 * 3600);
}
if (!empty($dailyPayload['Note']) || !empty($weeklyPayload['Note']) || !empty($monthlyPayload['Note'])) {
return [
'ok' => false,
'message' => 'Alpha Vantage Limit erreicht. Bitte spaeter erneut versuchen.',
];
}
$daily = $normalizeSeries($dailyPayload, ['Time Series (Daily)']);
$weekly = $normalizeSeries($weeklyPayload, ['Weekly Adjusted Time Series', 'Weekly Time Series']);
$monthly = $normalizeSeries($monthlyPayload, ['Monthly Adjusted Time Series', 'Monthly Time Series']);
if ($daily === [] && $weekly === [] && $monthly === []) {
return [
'ok' => false,
'message' => 'Keine Zeitreihendaten fuer ' . $symbol . ' verfuegbar.',
];
}
return [
'ok' => true,
'symbol' => $symbol,
'daily' => $daily,
'weekly' => $weekly,
'monthly' => $monthly,
];
});