|
6 | 6 | DEFAULT_STALE_PRICE_THRESHOLD_SECONDS = 5
|
7 | 7 |
|
8 | 8 |
|
| 9 | +class PriceUpdate: |
| 10 | + def __init__(self, price, timestamp): |
| 11 | + self.price = price |
| 12 | + self.timestamp = timestamp |
| 13 | + |
| 14 | + def __str__(self): |
| 15 | + return f"PriceUpdate(price={self.price}, timestamp={self.timestamp})" |
| 16 | + |
| 17 | + def time_diff(self, now): |
| 18 | + return now - self.timestamp |
| 19 | + |
| 20 | + |
9 | 21 | class PriceState:
|
10 | 22 | """
|
11 | 23 | Maintain latest prices seen across listeners and publisher.
|
12 | 24 | """
|
13 | 25 | def __init__(self, config: Config):
|
14 | 26 | self.stale_price_threshold_seconds = config.stale_price_threshold_seconds
|
15 |
| - now = time.time() |
16 | 27 |
|
17 |
| - self.hl_oracle_price = None |
18 |
| - self.hl_mark_price = None |
19 |
| - self.latest_hl_timestamp = now |
| 28 | + self.hl_oracle_price: PriceUpdate | None = None |
| 29 | + self.hl_mark_price: PriceUpdate | None = None |
20 | 30 |
|
21 |
| - self.lazer_base_price = None |
| 31 | + self.lazer_base_price: PriceUpdate | None = None |
22 | 32 | self.lazer_base_exponent = config.lazer.base_feed_exponent
|
23 |
| - self.lazer_quote_price = None |
| 33 | + self.lazer_quote_price: PriceUpdate | None = None |
24 | 34 | self.lazer_quote_exponent = config.lazer.quote_feed_exponent
|
25 |
| - self.latest_lazer_timestamp = now |
26 | 35 |
|
27 |
| - self.hermes_base_price = None |
| 36 | + self.hermes_base_price: PriceUpdate | None = None |
28 | 37 | self.hermes_base_exponent = config.hermes.base_feed_exponent
|
29 |
| - self.hermes_quote_price = None |
| 38 | + self.hermes_quote_price: PriceUpdate | None = None |
30 | 39 | self.hermes_quote_exponent = config.hermes.quote_feed_exponent
|
31 |
| - self.latest_hermes_timestamp = now |
32 | 40 |
|
33 | 41 | def get_current_oracle_price(self):
|
34 | 42 | now = time.time()
|
35 | 43 | if self.hl_oracle_price:
|
36 |
| - time_diff = now - self.latest_hl_timestamp |
| 44 | + time_diff = self.hl_oracle_price.time_diff(now) |
37 | 45 | if time_diff < self.stale_price_threshold_seconds:
|
38 |
| - return self.hl_oracle_price |
| 46 | + return self.hl_oracle_price.price |
39 | 47 | else:
|
40 | 48 | logger.error("Hyperliquid oracle price stale by {} seconds", time_diff)
|
41 | 49 | else:
|
42 | 50 | logger.error("Hyperliquid oracle price not received yet")
|
43 | 51 |
|
44 |
| - # fall back to Hermes |
45 |
| - if self.hermes_base_price and self.hermes_quote_price: |
46 |
| - time_diff = now - self.latest_hermes_timestamp |
47 |
| - if time_diff < self.stale_price_threshold_seconds: |
48 |
| - return self.get_hermes_price() |
49 |
| - else: |
50 |
| - logger.error("Hermes price stale by {} seconds", time_diff) |
51 |
| - else: |
52 |
| - logger.error("Hermes base/quote prices not received yet") |
53 |
| - |
54 | 52 | # fall back to Lazer
|
55 | 53 | if self.lazer_base_price and self.lazer_quote_price:
|
56 |
| - time_diff = now - self.latest_lazer_timestamp |
57 |
| - if time_diff < self.stale_price_threshold_seconds: |
| 54 | + max_time_diff = max(self.lazer_base_price.time_diff(now), self.lazer_quote_price.time_diff(now)) |
| 55 | + if max_time_diff < self.stale_price_threshold_seconds: |
58 | 56 | return self.get_lazer_price()
|
59 | 57 | else:
|
60 |
| - logger.error("Lazer price stale by {} seconds", time_diff) |
| 58 | + logger.error("Lazer price stale by {} seconds", max_time_diff) |
61 | 59 | else:
|
62 | 60 | logger.error("Lazer base/quote prices not received yet")
|
63 | 61 |
|
| 62 | + # fall back to Hermes |
| 63 | + if self.hermes_base_price and self.hermes_quote_price: |
| 64 | + max_time_diff = max(self.hermes_base_price.time_diff(now), self.hermes_quote_price.time_diff(now)) |
| 65 | + if max_time_diff < self.stale_price_threshold_seconds: |
| 66 | + return self.get_hermes_price() |
| 67 | + else: |
| 68 | + logger.error("Hermes price stale by {} seconds", max_time_diff) |
| 69 | + else: |
| 70 | + logger.error("Hermes base/quote prices not received yet") |
| 71 | + |
64 | 72 | logger.error("All prices missing or stale!")
|
65 | 73 | return None
|
66 | 74 |
|
67 | 75 | def get_hermes_price(self):
|
68 |
| - base_price = float(self.hermes_base_price) / (10.0 ** -self.hermes_base_exponent) |
69 |
| - quote_price = float(self.hermes_quote_price) / (10.0 ** -self.hermes_quote_exponent) |
| 76 | + base_price = float(self.hermes_base_price.price) / (10.0 ** -self.hermes_base_exponent) |
| 77 | + quote_price = float(self.hermes_quote_price.price) / (10.0 ** -self.hermes_quote_exponent) |
70 | 78 | return str(round(base_price / quote_price, 2))
|
71 | 79 |
|
72 | 80 | def get_lazer_price(self):
|
73 |
| - base_price = float(self.lazer_base_price) / (10.0 ** -self.lazer_base_exponent) |
74 |
| - quote_price = float(self.lazer_quote_price) / (10.0 ** -self.lazer_quote_exponent) |
| 81 | + base_price = float(self.lazer_base_price.price) / (10.0 ** -self.lazer_base_exponent) |
| 82 | + quote_price = float(self.lazer_quote_price.price) / (10.0 ** -self.lazer_quote_exponent) |
75 | 83 | return str(round(base_price / quote_price, 2))
|
0 commit comments