Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions core/apps/daemon/src/worker/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ pub enum WorkerJob {
CleanupChartsRaw,
CleanupChartsHourly,
UpdateMarkets,
UpdatePricesMetrics,
UpdateChartsHistory,
UpdateObservedPrices,
UpdatePricesAssets,
Expand Down Expand Up @@ -203,7 +202,6 @@ impl WorkerJob {
CleanupChartsRaw => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerCleanupChartsRaw)),
CleanupChartsHourly => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerCleanupChartsHourly)),
UpdateMarkets => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerMarkets)),
UpdatePricesMetrics => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerMetrics)),
UpdateChartsHistory => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerChartsHistory)),
UpdateObservedPrices => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceObservedFetchInterval)),
UpdatePricesAssets => JobSpec::new(WorkerService::Prices, JobInterval::Config(ConfigKey::PriceTimerAssets)),
Expand Down
11 changes: 0 additions & 11 deletions core/apps/daemon/src/worker/prices/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,6 @@ async fn add_provider_jobs<'a>(builder: JobPlanBuilder<'a>, prices: &PriceJobs,
}
});

let metrics_variant = JobVariant::labeled(WorkerJob::UpdatePricesMetrics, kind)
.with_param_duration(&config, &ConfigParamKey::PriceProviderMetricsDuration(kind))
.await?;
builder = builder.job(metrics_variant, {
let prices = prices.clone();
move |_| {
let updater = prices.metrics_updater(kind);
async move { updater.update().await }
}
});

let history_config = ChartsHistoryConfig {
hourly_duration: config.get_param_duration(&ConfigParamKey::PriceProviderChartsHourlyDuration(kind)).await?,
};
Expand Down
2 changes: 0 additions & 2 deletions core/crates/config_keys/src/config_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ pub enum ConfigKey {
PriceTimerChartsDaily,
PriceTimerMarkets,
PriceTimerPrices,
PriceTimerMetrics,
PriceTimerAssets,
PriceTimerAssetsNew,
PriceMetadataPublishInterval,
Expand Down Expand Up @@ -317,7 +316,6 @@ impl ConfigKey {
Self::PriceTimerChartsDaily => "1d",
Self::PriceTimerMarkets => "1h",
Self::PriceTimerPrices => "60s",
Self::PriceTimerMetrics => "5m",
Self::PriceTimerAssets => "1d",
Self::PriceTimerAssetsNew => "15m",
Self::PriceMetadataPublishInterval => "1m",
Expand Down
5 changes: 0 additions & 5 deletions core/crates/config_keys/src/config_param_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ pub enum ConfigParamKey {
PriceProviderAssetsMetadataDuration(PriceProvider),
PriceProviderPricesDuration(PriceProvider),
PriceProviderChartsHourlyDuration(PriceProvider),
PriceProviderMetricsDuration(PriceProvider),
PriceProviderCleanOutdatedDuration(PriceProvider),
ListProviderUpdateDuration(ListProviderName),
ScanProviderEnable(ScanProvider),
Expand All @@ -145,7 +144,6 @@ impl ConfigParamKey {
let assets_metadata = PriceProvider::all().into_iter().map(Self::PriceProviderAssetsMetadataDuration);
let prices = PriceProvider::all().into_iter().map(Self::PriceProviderPricesDuration);
let charts_hourly = PriceProvider::all().into_iter().map(Self::PriceProviderChartsHourlyDuration);
let metrics = PriceProvider::all().into_iter().map(Self::PriceProviderMetricsDuration);
let clean_outdated = PriceProvider::all().into_iter().map(Self::PriceProviderCleanOutdatedDuration);
let scan_providers = ScanProvider::all().into_iter().map(Self::ScanProviderEnable);
let scan_types = ScanType::all().into_iter().map(Self::ScanTypeEnable);
Expand All @@ -161,7 +159,6 @@ impl ConfigParamKey {
.chain(assets_metadata)
.chain(prices)
.chain(charts_hourly)
.chain(metrics)
.chain(clean_outdated)
.chain(lists)
.chain(scan_providers)
Expand All @@ -182,7 +179,6 @@ impl ConfigParamKey {
Self::PriceProviderAssetsMetadataDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::PriceProviderPricesDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::PriceProviderChartsHourlyDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::PriceProviderMetricsDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::PriceProviderCleanOutdatedDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::ListProviderUpdateDuration(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Self::ScanProviderEnable(provider) => format!("{}.{}", self.as_ref(), provider.as_ref()),
Expand All @@ -204,7 +200,6 @@ impl ConfigParamKey {
Self::PriceProviderAssetsMetadataDuration(_) => "30d".to_string(),
Self::PriceProviderPricesDuration(_) => "60s".to_string(),
Self::PriceProviderChartsHourlyDuration(_) => "7d".to_string(),
Self::PriceProviderMetricsDuration(_) => "5m".to_string(),
Self::PriceProviderCleanOutdatedDuration(_) => "1d".to_string(),
Self::ListProviderUpdateDuration(_) => "1d".to_string(),
Self::ScanProviderEnable(_) => "true".to_string(),
Expand Down
3 changes: 1 addition & 2 deletions core/crates/jupiter/src/model/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ pub struct TokenAudit {
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[serde(rename_all = "camelCase")]
pub struct TokenStats {
#[serde(default)]
pub price_change: f64,
pub price_change: Option<f64>,
pub buy_volume: Option<f64>,
pub sell_volume: Option<f64>,
}
Expand Down
19 changes: 14 additions & 5 deletions core/crates/prices/src/alerts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ impl PriceAlertRules {

if let Some(target_percent) = price_alert.price_percent_change {
let direction = price_alert.price_direction.as_ref()?;
let price_change = price_data.price_change_percentage_24h?;
return match direction {
PriceAlertDirection::Up if price_data.price_change_percentage_24h >= target_percent => Some((PriceAlertType::PricePercentChangeUp, None)),
PriceAlertDirection::Down if price_data.price_change_percentage_24h <= -target_percent => Some((PriceAlertType::PricePercentChangeDown, None)),
PriceAlertDirection::Up if price_change >= target_percent => Some((PriceAlertType::PricePercentChangeUp, None)),
PriceAlertDirection::Down if price_change <= -target_percent => Some((PriceAlertType::PricePercentChangeDown, None)),
_ => None,
};
}
Expand All @@ -52,16 +53,17 @@ impl PriceAlertRules {
return Some((PriceAlertType::AllTimeHigh, None));
}

let price_24h_ago = price_24h_ago(price, price_data.price_change_percentage_24h);
let price_change = price_data.price_change_percentage_24h?;
let price_24h_ago = price_24h_ago(price, price_change);
if let Some(milestone) = self.crossed_milestone(price_24h_ago, price) {
return Some((PriceAlertType::PriceMilestone, Some(milestone)));
}

let threshold = self.change_threshold(price_data.market_cap_rank.unwrap_or(0));
if price_data.price_change_percentage_24h > threshold {
if price_change > threshold {
return Some((PriceAlertType::PriceChangesUp, None));
}
if price_data.price_change_percentage_24h < -threshold {
if price_change < -threshold {
return Some((PriceAlertType::PriceChangesDown, None));
}

Expand Down Expand Up @@ -164,6 +166,13 @@ mod tests {
assert_eq!(rules.evaluate(&auto, &device(Currency::EUR), &PriceData::mock_with(78_987.0, 6.0), &TEST_RATES), trigger(PriceAlertType::PriceChangesUp, EUR));
assert_eq!(rules.evaluate(&auto, &device(Currency::JPY), &PriceData::mock_with(78_987.0, 6.0), &TEST_RATES), None);
assert_eq!(rules.evaluate(&auto, &usd, &PriceData::mock_with(78_987.0, 1.0), &TEST_RATES), None);
let unknown_change = PriceData {
price_change_percentage_24h: None,
..PriceData::mock_with(78_987.0, 0.0)
};
assert_eq!(rules.evaluate(&percent_up, &usd, &unknown_change, &TEST_RATES), None);
assert_eq!(rules.evaluate(&auto, &usd, &unknown_change, &TEST_RATES), None);
assert_eq!(rules.evaluate(&under, &usd, &unknown_change, &TEST_RATES), target(PriceAlertType::PriceDown, 71_000.0, EUR));
assert_eq!(
rules.evaluate(
&auto,
Expand Down
40 changes: 23 additions & 17 deletions core/crates/prices/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chrono::Utc;
use primitives::{AssetId, AssetLink, AssetMarket, Price, PriceData, PriceId, PriceProvider};
use chrono::{DateTime, Utc};
use primitives::{AssetId, AssetLink, AssetMarket, PriceData, PriceId, PriceProvider};

#[derive(Debug, Clone)]
pub struct AssetPriceMapping {
Expand Down Expand Up @@ -57,35 +57,41 @@ impl PriceProviderAssetMetadata {
#[derive(Debug, Clone)]
pub struct AssetPriceFull {
pub mapping: AssetPriceMapping,
pub price: Price,
pub price: f64,
pub price_change_percentage_24h: Option<f64>,
pub updated_at: DateTime<Utc>,
pub provider: PriceProvider,
pub market: Option<AssetMarket>,
}

impl AssetPriceFull {
pub fn new(mapping: AssetPriceMapping, price: Price, market: Option<AssetMarket>) -> Self {
Self { mapping, price, market }
pub fn new(mapping: AssetPriceMapping, price: f64, price_change_percentage_24h: Option<f64>, updated_at: DateTime<Utc>, provider: PriceProvider, market: Option<AssetMarket>) -> Self {
Self {
mapping,
price,
price_change_percentage_24h,
updated_at,
provider,
market,
}
}

pub fn simple(mapping: AssetPriceMapping, price: f64, price_change_percentage_24h: f64, provider: PriceProvider) -> Self {
Self::new(mapping, Price::new(price, price_change_percentage_24h, Utc::now(), provider), None)
pub fn simple(mapping: AssetPriceMapping, price: f64, price_change_percentage_24h: Option<f64>, provider: PriceProvider) -> Self {
Self::new(mapping, price, price_change_percentage_24h, Utc::now(), provider, None)
}

pub fn from_provider_asset(asset: PriceProviderAsset, provider: PriceProvider) -> Self {
Self::new(
asset.mapping,
Price::new(asset.price.unwrap_or_default(), asset.price_change_percentage_24h.unwrap_or_default(), Utc::now(), provider),
asset.market,
)
Self::new(asset.mapping, asset.price.unwrap_or_default(), asset.price_change_percentage_24h, Utc::now(), provider, asset.market)
}

pub fn as_price_data(&self) -> PriceData {
let market = self.market.clone().unwrap_or_default();
PriceData {
id: PriceId::new(self.price.provider, self.mapping.provider_price_id.clone()),
provider: self.price.provider,
id: PriceId::new(self.provider, self.mapping.provider_price_id.clone()),
provider: self.provider,
provider_price_id: self.mapping.provider_price_id.clone(),
price: self.price.price,
price_change_percentage_24h: self.price.price_change_percentage_24h,
price: self.price,
price_change_percentage_24h: self.price_change_percentage_24h,
all_time_high: market.all_time_high.unwrap_or_default(),
all_time_high_date: market.all_time_high_date,
all_time_low: market.all_time_low.unwrap_or_default(),
Expand All @@ -97,7 +103,7 @@ impl AssetPriceFull {
circulating_supply: market.circulating_supply,
total_supply: market.total_supply,
max_supply: market.max_supply,
last_updated_at: self.price.updated_at,
last_updated_at: self.updated_at,
}
}
}
20 changes: 16 additions & 4 deletions core/crates/prices/src/providers/coingecko/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;

use chrono::{DateTime, Utc};
use coingecko::{Coin, CoinInfo, CoinMarket, get_asset_ids_for_coin, model::MarketChart};
use primitives::{AssetId, AssetLink, AssetMarket, ChartValue, ChartValuePercentage, LinkType, OptionStringExt, Price, PriceProvider};
use primitives::{AssetId, AssetLink, AssetMarket, ChartValue, ChartValuePercentage, LinkType, OptionStringExt, PriceProvider};

use crate::{AssetPriceFull, AssetPriceMapping, PriceProviderAsset, PriceProviderAssetMetadata};

Expand Down Expand Up @@ -53,7 +53,7 @@ pub fn map_coin_market(market: CoinMarket, mapping: AssetPriceMapping) -> AssetP
let updated_at = market.last_updated.unwrap_or_else(Utc::now);
let price = market.current_price.unwrap_or_default();
let market_data = coin_market_to_asset_market(&market);
AssetPriceFull::new(mapping, Price::new(price, market.price_change_percentage_24h.unwrap_or_default(), updated_at, PriceProvider::Coingecko), Some(market_data))
AssetPriceFull::new(mapping, price, market.price_change_percentage_24h, updated_at, PriceProvider::Coingecko, Some(market_data))
}

pub fn coin_market_to_asset_market(market: &CoinMarket) -> AssetMarket {
Expand Down Expand Up @@ -204,9 +204,21 @@ mod tests {
assert_eq!(prices[0].mapping.provider_price_id, ethereum.provider_price_id);
assert_eq!(prices[1].mapping.asset_id, smartchain.asset_id);
assert_eq!(prices[1].mapping.provider_price_id, smartchain.provider_price_id);
assert_eq!(prices[0].price.price, 0.12);
assert_eq!(prices[1].price.price, 0.12);
assert_eq!(prices[0].price, 0.12);
assert_eq!(prices[1].price, 0.12);
assert_eq!(prices[0].market.as_ref().and_then(|m| m.total_volume), Some(10.0));
assert_eq!(prices[1].market.as_ref().and_then(|m| m.total_volume), Some(10.0));
}

#[test]
fn test_map_coin_market_keeps_unknown_price_change() {
let mapping = AssetPriceMapping::new(AssetId::from_chain(Chain::Bitcoin), "bitcoin".to_string());
let unknown = CoinMarket {
price_change_percentage_24h: None,
..CoinMarket::mock_with_id("bitcoin")
};

assert_eq!(map_coin_market(unknown, mapping.clone()).as_price_data().price_change_percentage_24h, None);
assert_eq!(map_coin_market(CoinMarket::mock_with_id("bitcoin"), mapping).as_price_data().price_change_percentage_24h, Some(1.5));
}
}
8 changes: 4 additions & 4 deletions core/crates/prices/src/providers/defillama/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub fn asset_ids_for_defillama_id(provider_price_id: &str) -> Vec<AssetId> {
}

pub fn map_price(mapping: AssetPriceMapping, coin: &CoinPrice) -> AssetPriceFull {
AssetPriceFull::simple(mapping, coin.price, 0.0, PriceProvider::DefiLlama)
AssetPriceFull::simple(mapping, coin.price, None, PriceProvider::DefiLlama)
}

fn chain_to_defillama_slug(chain: Chain) -> Option<&'static str> {
Expand Down Expand Up @@ -100,9 +100,9 @@ mod tests {

let full = map_price(mapping, coin);

assert_eq!(full.price.price, 67000.0);
assert_eq!(full.price.price_change_percentage_24h, 0.0);
assert_eq!(full.price.provider, PriceProvider::DefiLlama);
assert_eq!(full.price, 67000.0);
assert_eq!(full.price_change_percentage_24h, None);
assert_eq!(full.provider, PriceProvider::DefiLlama);
assert!(full.market.is_none());
}
}
12 changes: 6 additions & 6 deletions core/crates/prices/src/providers/jupiter/mapper.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ::jupiter::Token;
use primitives::{AssetId, AssetMarket, Chain, Price, PriceProvider, contract_constants::SOLANA_WRAPPED_SOL_TOKEN_ADDRESS};
use primitives::{AssetId, AssetMarket, Chain, PriceProvider, contract_constants::SOLANA_WRAPPED_SOL_TOKEN_ADDRESS};

use crate::{AssetPriceFull, AssetPriceMapping, PriceProviderAsset};

Expand All @@ -20,11 +20,11 @@ pub fn to_jupiter_token_id(provider_price_id: &str) -> String {
}

pub fn map_token_asset(token: Token) -> PriceProviderAsset {
PriceProviderAsset::with_price(to_asset_price_mapping(&token.id), Some(map_token_market(&token)), Some(token.usd_price), Some(token.stats24h.price_change))
PriceProviderAsset::with_price(to_asset_price_mapping(&token.id), Some(map_token_market(&token)), Some(token.usd_price), token.stats24h.price_change)
}

pub fn map_token_price(mapping: AssetPriceMapping, token: &Token) -> AssetPriceFull {
AssetPriceFull::new(mapping, Price::new(token.usd_price, token.stats24h.price_change, chrono::Utc::now(), PriceProvider::Jupiter), Some(map_token_market(token)))
AssetPriceFull::new(mapping, token.usd_price, token.stats24h.price_change, chrono::Utc::now(), PriceProvider::Jupiter, Some(map_token_market(token)))
}

fn map_token_market(token: &Token) -> AssetMarket {
Expand Down Expand Up @@ -70,7 +70,7 @@ mod tests {
circ_supply: Some(5.0),
total_supply: Some(10.0),
stats24h: TokenStats {
price_change: 3.0,
price_change: Some(3.0),
buy_volume: Some(30.0),
sell_volume: Some(40.0),
},
Expand All @@ -79,8 +79,8 @@ mod tests {
let price = map_token_price(AssetPriceMapping::new(AssetId::from_token(Chain::Solana, "token"), "token".to_string()), &token);
let market = price.market.unwrap();

assert_eq!(price.price.price, 2.0);
assert_eq!(price.price.price_change_percentage_24h, 3.0);
assert_eq!(price.price, 2.0);
assert_eq!(price.price_change_percentage_24h, Some(3.0));
assert_eq!(market.market_cap, Some(10.0));
assert_eq!(market.market_cap_fdv, Some(20.0));
assert_eq!(market.total_volume, Some(70.0));
Expand Down
6 changes: 3 additions & 3 deletions core/crates/prices/src/providers/pyth/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl PriceAssetsProvider for PythProvider {

Ok(mappings
.into_iter()
.filter_map(|mapping| prices_by_feed_id.get(&mapping.provider_price_id).map(|price| AssetPriceFull::simple(mapping, *price, 0.0, PriceProvider::Pyth)))
.filter_map(|mapping| prices_by_feed_id.get(&mapping.provider_price_id).map(|price| AssetPriceFull::simple(mapping, *price, None, PriceProvider::Pyth)))
.collect())
}
}
Expand Down Expand Up @@ -88,8 +88,8 @@ mod price_integration_tests {
let mapping = AssetPriceMapping::new(Chain::Bitcoin.as_asset_id(), feed_id.to_string());
let prices = provider.get_prices(vec![mapping]).await?;
assert_eq!(prices.len(), 1);
assert!(prices[0].price.price.is_finite());
assert!(prices[0].price.price > 0.0);
assert!(prices[0].price.is_finite());
assert!(prices[0].price > 0.0);
Ok(())
}
}
12 changes: 6 additions & 6 deletions core/crates/prices/src/providers/tonapi/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn map_price(mapping: AssetPriceMapping, response: &RatesResponse) -> Option
if !price.is_finite() || price <= 0.0 {
return None;
}
let price_change_percentage_24h = rates.diff_24h.get("USD").and_then(|value| value.trim_end_matches('%').replace('−', "-").parse::<f64>().ok()).unwrap_or_default();
let price_change_percentage_24h = rates.diff_24h.get("USD").and_then(|value| value.trim_end_matches('%').replace('−', "-").parse::<f64>().ok());
Some(AssetPriceFull::simple(mapping, price, price_change_percentage_24h, PriceProvider::TonApi))
}

Expand Down Expand Up @@ -89,13 +89,13 @@ mod tests {
assert_eq!(mapping_for_stonfi_asset(excluded).map(|mapping| mapping.asset_id), None);

let response: RatesResponse = serde_json::from_str(include_str!("../../../testdata/tonapi/rates.json")).unwrap();
let native_price = map_price(mapping_for_asset_id(&native).unwrap(), &response).unwrap().price;
let native_price = map_price(mapping_for_asset_id(&native).unwrap(), &response).unwrap();
assert_eq!(native_price.price, 3.42);
assert_eq!(native_price.price_change_percentage_24h, -4.58);
let dust_price = map_price(mapping_for_asset_id(&dust).unwrap(), &response).unwrap().price;
assert_eq!(native_price.price_change_percentage_24h, Some(-4.58));
let dust_price = map_price(mapping_for_asset_id(&dust).unwrap(), &response).unwrap();
assert_eq!(dust_price.price, 0.62784);
assert_eq!(dust_price.price_change_percentage_24h, 2.14);
assert_eq!(dust_price.price_change_percentage_24h, Some(2.14));
let zero = AssetPriceMapping::new(dust, "ZERO".to_string());
assert_eq!(map_price(zero, &response).map(|price| price.price.price), None);
assert_eq!(map_price(zero, &response).map(|price| price.price), None);
}
}
Loading
Loading