Skip to content

Commit 195e81a

Browse files
authored
refactor observer (#58)
* refactor observer * fix pre-commit * remove duplicate code * bump
1 parent 608e906 commit 195e81a

File tree

7 files changed

+1151
-1013
lines changed

7 files changed

+1151
-1013
lines changed

poetry.lock

+1,116-902
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ ignore_missing_imports = true
44

55
[tool.poetry]
66
name = "pyth-observer"
7-
version = "0.1.12"
7+
version = "0.1.13"
88
description = "Alerts and stuff"
99
authors = []
1010
readme = "README.md"
@@ -20,9 +20,8 @@ datadog-api-client = { extras = ["async"], version = "^2.5.0" }
2020
loguru = "^0.6.0"
2121
more-itertools = "^9.0.0"
2222
prometheus-client = "0.15.0"
23-
pytz = "^2022.4"
2423
pycoingecko = "2.2.0"
25-
pythclient = "0.1.4"
24+
pythclient = "^0.1.24"
2625
pyyaml = "^6.0"
2726
throttler = "1.2.1"
2827
types-pyyaml = "^6.0.12"

pyth_observer/__init__.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -94,25 +94,34 @@ async def run(self):
9494
)
9595

9696
for _, price_account in price_accounts.items():
97+
# Handle potential None for min_publishers
98+
if (
99+
price_account.min_publishers is None
100+
# When min_publishers is high it means that the price is not production-ready
101+
# yet and it is still being tested. We need no alerting for these prices.
102+
or price_account.min_publishers >= 10
103+
):
104+
continue
105+
106+
# Ensure latest_block_slot is not None or provide a default value
107+
latest_block_slot = (
108+
price_account.slot if price_account.slot is not None else -1
109+
)
110+
97111
if not price_account.aggregate_price_status:
98112
raise RuntimeError("Price account status is missing")
99113

100114
if not price_account.aggregate_price_info:
101115
raise RuntimeError("Aggregate price info is missing")
102116

103-
# When min_publishers is high it means that the price is not production-ready
104-
# yet and it is still being tested. We need no alerting for these prices.
105-
if price_account.min_publishers >= 10:
106-
continue
107-
108117
states.append(
109118
PriceFeedState(
110119
symbol=product.attrs["symbol"],
111120
asset_type=product.attrs["asset_type"],
112121
public_key=price_account.key,
113122
status=price_account.aggregate_price_status,
114123
# this is the solana block slot when price account was fetched
115-
latest_block_slot=price_account.slot,
124+
latest_block_slot=latest_block_slot,
116125
latest_trading_slot=price_account.last_slot,
117126
price_aggregate=price_account.aggregate_price_info.price,
118127
confidence_interval_aggregate=price_account.aggregate_price_info.confidence_interval,
@@ -141,7 +150,7 @@ async def run(self):
141150
slot=component.latest_price_info.pub_slot,
142151
aggregate_slot=price_account.last_slot,
143152
# this is the solana block slot when price account was fetched
144-
latest_block_slot=price_account.slot,
153+
latest_block_slot=latest_block_slot,
145154
status=component.latest_price_info.price_status,
146155
aggregate_status=price_account.aggregate_price_status,
147156
)

pyth_observer/calendar.py

-68
This file was deleted.

pyth_observer/check/price_feed.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import datetime
21
import time
32
from dataclasses import dataclass
3+
from datetime import datetime
44
from textwrap import dedent
55
from typing import Dict, Optional, Protocol, runtime_checkable
6+
from zoneinfo import ZoneInfo
67

78
import arrow
8-
import pytz
9+
from pythclient.calendar import is_market_open
910
from pythclient.pythaccounts import PythPriceStatus
1011
from pythclient.solana import SolanaPublicKey
1112

12-
from pyth_observer.calendar import HolidayCalendar
1313
from pyth_observer.crosschain import CrosschainPrice
1414

1515

@@ -56,13 +56,13 @@ def state(self) -> PriceFeedState:
5656
return self.__state
5757

5858
def run(self) -> bool:
59-
is_market_open = HolidayCalendar().is_market_open(
59+
market_open = is_market_open(
6060
self.__state.asset_type,
61-
datetime.datetime.now(tz=pytz.timezone("America/New_York")),
61+
datetime.now(ZoneInfo("America/New_York")),
6262
)
6363

6464
# Skip if market is not open
65-
if not is_market_open:
65+
if not market_open:
6666
return True
6767

6868
distance = abs(
@@ -181,13 +181,13 @@ def run(self) -> bool:
181181
if self.__state.status != PythPriceStatus.TRADING:
182182
return True
183183

184-
is_market_open = HolidayCalendar().is_market_open(
184+
market_open = is_market_open(
185185
self.__state.asset_type,
186-
datetime.datetime.now(tz=pytz.timezone("America/New_York")),
186+
datetime.now(ZoneInfo("America/New_York")),
187187
)
188188

189189
# Skip if not trading hours (for equities)
190-
if not is_market_open:
190+
if not market_open:
191191
return True
192192

193193
# Price should exist, it fails otherwise
@@ -243,13 +243,13 @@ def run(self) -> bool:
243243
if self.__state.status != PythPriceStatus.TRADING:
244244
return True
245245

246-
is_market_open = HolidayCalendar().is_market_open(
246+
market_open = is_market_open(
247247
self.__state.asset_type,
248-
datetime.datetime.now(tz=pytz.timezone("America/New_York")),
248+
datetime.now(ZoneInfo("America/New_York")),
249249
)
250250

251251
# Skip if not trading hours (for equities)
252-
if not is_market_open:
252+
if not market_open:
253253
return True
254254

255255
staleness = int(time.time()) - self.__state.crosschain_price["publish_time"]

pyth_observer/event.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
from datadog_api_client.configuration import Configuration as DatadogConfig
66
from datadog_api_client.v1.api.events_api import EventsApi as DatadogEventAPI
77
from datadog_api_client.v1.model.event_alert_type import EventAlertType
8-
from datadog_api_client.v1.model.event_create_request import (
9-
EventCreateRequest as DatadogAPIEvent,
10-
)
8+
from datadog_api_client.v1.model.event_create_request import EventCreateRequest
119
from loguru import logger
1210

1311
from pyth_observer.check import Check
@@ -45,7 +43,7 @@ async def send(self):
4543
# An example would be: PublisherPriceCheck-Crypto.AAVE/USD-9TvAYCUkGajRXs....
4644
aggregation_key += "-" + self.check.state().public_key.key
4745

48-
event = DatadogAPIEvent(
46+
event = EventCreateRequest(
4947
aggregation_key=aggregation_key,
5048
title=text.split("\n")[0],
5149
text=text,
@@ -59,6 +57,9 @@ async def send(self):
5957
source_type_name="my_apps",
6058
)
6159

60+
# Cast the event to EventCreateRequest explicitly because pyright complains that the previous line returns UnparsedObject | Unknown | None
61+
event = cast(EventCreateRequest, event)
62+
6263
# This assumes that DD_API_KEY and DD_SITE env. variables are set. Also,
6364
# using the async API makes the events api return a coroutine, so we
6465
# ignore the pyright warning.

requirements.txt

-17
This file was deleted.

0 commit comments

Comments
 (0)