boerse
This commit is contained in:
@@ -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,
|
||||
];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user