diff --git a/container/src/finance/lib/internal/fetch/prices/internal/base.php b/container/src/finance/lib/internal/fetch/prices/internal/base.php index 8afbacb..5039c73 100644 --- a/container/src/finance/lib/internal/fetch/prices/internal/base.php +++ b/container/src/finance/lib/internal/fetch/prices/internal/base.php @@ -192,12 +192,68 @@ namespace docker_finance\prices\internal abstract protected function make_timestamp(string $year): mixed; /** - * @brief Parse fetched prices by symbol - * @param string $symbol Given symbol associated with ID - * @param array $prices Array of [N]([timestamp][price])for given year(s) - * @return array Prices for all given symbols + * @brief Make daily average of given prices + * @param array $prices Parsed [date => price] entries + * @return array Daily averages in date and price format (one per line) */ - abstract protected function parse_prices(string $symbol, array $prices): array; + private function make_average(array $prices): array + { + $total = 0; + $prev_date = ""; + $date_counter = 0; + + $stack = []; + + foreach ($prices as $date => $price) { + + // Either a kick-off date or a single daily average (per their API) + // NOTE: this *MUST* be overwritten below if computing non-daily + if ($prev_date == "") { + $stack[$date] = $price; + } + + // Average will be based on received dates + if ($prev_date == $date) { + $total += $price; + $date_counter++; + } else { + // Aggregator provided a single date, treat as the daily average + if (!$total) { + $total = $price; + } + + // Avoid divide by zero (if only a single date was provided) + if (!$date_counter) { + $date_counter = 1; + } + + // Finished previous date, calculate and push to stack + $average = $total / $date_counter; + + // Always overwrite with most recent daily average + if ($date_counter > 1) { + $stack[$prev_date] = $average; + } else { + $stack[$date] = $average; + } + + $total = 0; + $date_counter = 0; + } + + $prev_date = $date; + } + + utils\CLI::print_debug($stack); + return $stack; + } + + /** + * @brief Parse fetched date and prices + * @param array $prices Fetched prices [N]([timestamp][price]) + * @return array Date and prices without ID or symbol + */ + abstract protected function parse_prices(array $prices): array; /** * @brief Create data for master price journal file @@ -300,7 +356,7 @@ namespace docker_finance\prices\internal public function reader(string $symbols): array { - // Fetched prices for given symbols + // Prepared price journal for given symbols $stack = []; // Timestamp based on given year @@ -309,11 +365,11 @@ namespace docker_finance\prices\internal utils\CLI::print_normal(" ─ Symbols"); foreach ($this->parse_symbols($symbols) as $id => $symbol) { - $parsed = $this->parse_prices( - $symbol, - $this->getter($id, $timestamp) - ); - array_push($stack, $this->make_master($symbol, $parsed)); + $parsed = $this->parse_prices($this->getter($id, $timestamp)); + $master = $this->make_master($symbol, $this->make_average($parsed)); + + utils\CLI::print_debug($master); + array_push($stack, $master); } utils\CLI::print_custom(" \e[32m│\e[0m\n"); diff --git a/container/src/finance/lib/internal/fetch/prices/internal/prices/crypto.php b/container/src/finance/lib/internal/fetch/prices/internal/prices/crypto.php index fa282d7..852d246 100644 --- a/container/src/finance/lib/internal/fetch/prices/internal/prices/crypto.php +++ b/container/src/finance/lib/internal/fetch/prices/internal/prices/crypto.php @@ -76,9 +76,8 @@ namespace docker_finance\prices\internal\prices\crypto } /** - * @brief Parse given prices for given symbol - * @param string $symbol Given symbol associated with CoinGecko's ID - * @param array $prices Array of [N]([timestamp][price])for given year(s) + * @brief Parse fetched date and prices + * @param array $prices Fetched prices [N]([timestamp][price]) * @details * * Parses historical market data include price, market cap @@ -89,36 +88,36 @@ namespace docker_finance\prices\internal\prices\crypto * - 1 - 90 days from current time = hourly data * above 90 days from current time = daily data (00:00 UTC) * - * @return array Prices for all given symbols + * @return array Date and prices without ID or symbol */ - protected function parse_prices(string $symbol, array $prices): array + protected function parse_prices(array $prices): array { $total = 0; $prev_date = ""; $date_counter = 0; - $prices_stack = []; // date => daily average price + $stack = []; for($i = 0; $i < count($prices); $i++) { /** * Expectation: + * * array[0] = oldest entry - * array[N][0] = timestamp - * array[N][1] = price + * array[0][0] = timestamp + * array[0][1] = price * * array[1] = next hour - * array[N][0] = timestamp - * array[N][1] = price + * array[1][0] = timestamp + * array[1][1] = price + * * ...etc. */ $timestamp = $prices[$i][0] / 1000; $date = date('Y/m/d', $timestamp); + // Isolate given year. // - // Isolate given year - // - // If 'all', then all years are needed. Otherwise, for example, // if the given year is for last year, and the beginning of last // year was 375 days ago, then upstream will send 375 entries @@ -129,56 +128,13 @@ namespace docker_finance\prices\internal\prices\crypto continue; } $price = $prices[$i][1]; - utils\CLI::print_debug("$date = $price"); - // - // Get daily average - // - - // Either a kick-off date for hourlies or a single average (per their API) - // NOTE: this *MUST* be overwritten below if computing hourly - if ($prev_date == "") { - $prices_stack[$date] = $price; - } - - // Average will be based on hourly - // TODO: they volume-weight their real-time average. However, - // based on the data they provid to API clients, how do they - // calculate their *daily* average? It's not opening/closing - // (based on what they provide) or averaging their hourly. - // This can be confirmed when given a previous year or 'max'. - if ($prev_date == $date) { - $total += $price; - $date_counter++; - } else { - // They provided a single date, and *that* is the daily average - if (!$total) { - $total = $price; - } - - // Avoid divide by zero (if only a single date was provided) - if (!$date_counter) { - $date_counter = 1; - } - - // Finished previous date, calculate and push to stack - $average = $total / $date_counter; - - // Always overwrite with most recent daily average - if ($date_counter > 1) { - $prices_stack[$prev_date] = $average; - } else { - $prices_stack[$date] = $average; - } - - $total = 0; - $date_counter = 0; - } - - $prev_date = $date; + // Push to stack + $stack += [$date => $price]; } - return $prices_stack; + utils\CLI::print_debug($stack); + return $stack; } /** @@ -255,18 +211,13 @@ namespace docker_finance\prices\internal\prices\crypto } /** - * @brief Parse given prices for given symbol - * @param string $symbol Given symbol associated with Mobula's ID - * @param array $prices Array of [N]([timestamp][price])for given year(s) - * @return array Prices for all given symbols + * @brief Parse fetched date and prices + * @param array $prices Fetched prices [N]([timestamp][price])for given year(s) + * @return array Date and prices without ID or symbol */ - protected function parse_prices(string $symbol, array $prices): array + protected function parse_prices(array $prices): array { - $total = 0; - $prev_date = ""; - $date_counter = 0; - - $stack = []; // date => daily average price + $stack = []; for($i = 0; $i < count($prices); $i++) { /** @@ -287,50 +238,10 @@ namespace docker_finance\prices\internal\prices\crypto $date = date('Y/m/d', $timestamp); $price = $prices[$i][1]; - utils\CLI::print_debug("$date = $price"); - - // - // Get daily average - // - - // Either a kick-off date or a single daily average (per their API) - // NOTE: this *MUST* be overwritten below if computing non-daily - if ($prev_date == "") { - $stack[$date] = $price; - } - - // Average will be based on given dates (currently every 6 hours or 5 minutes) - if ($prev_date == $date) { - $total += $price; - $date_counter++; - } else { - // They provided a single date, and *that* is the daily average - if (!$total) { - $total = $price; - } - - // Avoid divide by zero (if only a single date was provided) - if (!$date_counter) { - $date_counter = 1; - } - - // Finished previous date, calculate and push to stack - $average = $total / $date_counter; - - // Always overwrite with most recent daily average - if ($date_counter > 1) { - $stack[$prev_date] = $average; - } else { - $stack[$date] = $average; - } - - $total = 0; - $date_counter = 0; - } - - $prev_date = $date; + $stack += [$date => $price]; } + utils\CLI::print_debug($stack); return $stack; }