php: fetch: prices: add Mobula support

This commit is contained in:
2024-06-15 22:56:57 -07:00
parent 55c893e010
commit 9d1c0c9c57

View File

@@ -214,6 +214,145 @@ namespace docker_finance\prices\internal\prices\crypto
return 'max';
}
}
/**
* @brief Mobula price aggregator API
* @since docker-finance 1.0.0
*/
final class Mobula extends internal\Impl
{
public function __construct(utils\Env $env)
{
parent::__construct($env);
}
/**
* @brief REST API request generator
* @param string $id Symbol's ID to request
* @param string $timestamp Timestamp to request
* @return mixed REST API response data
*/
protected function request(string $id, string $timestamp): mixed
{
// If `key` exists, append to header (used in all plans)
$key = $this->get_env()->get_env('API_PRICES_KEY');
$domain = 'api.mobula.io';
$header = [];
if ($key != 'None') {
$header = ["Authorization: $key"];
}
$url = "https://{$domain}/api/1/market/history?asset={$id}&from={$timestamp}";
$response = $this->request_impl($url, $header);
if (array_key_exists('error', $response)) {
throw new \Exception($response['error']);
}
$prices = $response['data']['price_history'];
utils\CLI::print_debug($prices);
return $prices;
}
/**
* @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
*/
protected function parse_prices(string $symbol, array $prices): array
{
$total = 0;
$prev_date = "";
$date_counter = 0;
$stack = []; // date => daily average price
for($i = 0; $i < count($prices); $i++) {
/**
* Expectation:
*
* array[0] = oldest entry
* array[0][0] = timestamp
* array[0][1] = price
*
* array[1] = next entry
* array[1][0] = timestamp
* array[1][1] = price
*
* ...etc.
*/
$timestamp = $prices[$i][0] / 1000;
$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;
}
return $stack;
}
/**
* @brief Make Mobula timestamp used in request
* @param string $year Given year
* @return mixed Unix timestamp in milliseconds
*/
protected function make_timestamp(string $year): mixed
{
// Number of days back to beginning of given year
if ($year != 'all') {
$timestamp = strtotime($this->get_env()->get_env('API_FETCH_YEAR') . '-01-01') * 1000;
utils\CLI::print_debug($timestamp);
return $timestamp;
}
// From genesis to present
return "";
}
}
} // namespace docker_finance\prices\internal\prices\crypto
//! @since docker-finance 1.0.0
@@ -244,6 +383,26 @@ namespace docker_finance\prices\internal\prices
$this->api->fetcher();
}
}
/**
* @brief Facade for Mobula implementation
* @ingroup php_prices
* @since docker-finance 1.0.0
*/
final class Mobula extends \docker_finance\prices\API
{
private crypto\Mobula $api; //!< Internal API
public function __construct(utils\Env $env)
{
$this->api = new crypto\Mobula($env);
}
public function fetch(): void
{
$this->api->fetcher();
}
}
} // namespace docker_finance\prices\internal\prices
# vim: sw=4 sts=4 si ai et