forked from EvergreenCrypto/docker-finance
php: fetch: prices: add Mobula support
This commit is contained in:
@@ -214,6 +214,145 @@ namespace docker_finance\prices\internal\prices\crypto
|
|||||||
return 'max';
|
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
|
} // namespace docker_finance\prices\internal\prices\crypto
|
||||||
|
|
||||||
//! @since docker-finance 1.0.0
|
//! @since docker-finance 1.0.0
|
||||||
@@ -244,6 +383,26 @@ namespace docker_finance\prices\internal\prices
|
|||||||
$this->api->fetcher();
|
$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
|
} // namespace docker_finance\prices\internal\prices
|
||||||
|
|
||||||
# vim: sw=4 sts=4 si ai et
|
# vim: sw=4 sts=4 si ai et
|
||||||
|
|||||||
Reference in New Issue
Block a user