forked from EvergreenCrypto/docker-finance
php: fetch: prices: refactor parsing; common impl
- Move daily average into common impl - Update parsing function signature - Update documentation
This commit is contained in:
@@ -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<mixed> $prices Array of [N]([timestamp][price])for given year(s)
|
||||
* @return array<string> Prices for all given symbols
|
||||
* @brief Make daily average of given prices
|
||||
* @param array<mixed> $prices Parsed [date => price] entries
|
||||
* @return array<string> 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<mixed> $prices Fetched prices [N]([timestamp][price])
|
||||
* @return array<string> 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");
|
||||
|
||||
@@ -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<mixed> $prices Array of [N]([timestamp][price])for given year(s)
|
||||
* @brief Parse fetched date and prices
|
||||
* @param array<mixed> $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<string> Prices for all given symbols
|
||||
* @return array<string> 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<mixed> $prices Array of [N]([timestamp][price])for given year(s)
|
||||
* @return array<string> Prices for all given symbols
|
||||
* @brief Parse fetched date and prices
|
||||
* @param array<mixed> $prices Fetched prices [N]([timestamp][price])for given year(s)
|
||||
* @return array<string> 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user