Skip to content

Commit cb2e089

Browse files
authored
feat: add Lbank + Bitget fetchers (#256)
* feat: add bitget fetcher * feat: add lbank fetcher * feat: add dog support * bump version
1 parent e29dda8 commit cb2e089

12 files changed

Lines changed: 278 additions & 6 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.5.1"
1+
__version__ = "2.6.0"

infra/price-pusher/config/config.mainnet.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- USDC/USD
1010
- USDT/USD
1111
- DAI/USD
12+
- DOG/USD
1213
time_difference: 600
1314
price_deviation: 0.005
1415

lp-pricer/lp_pricer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.5.1"
1+
__version__ = "2.6.0"

pragma-sdk/pragma_sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.5.1"
1+
__version__ = "2.6.0"

pragma-sdk/pragma_sdk/common/fetchers/fetchers/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from pragma_sdk.common.fetchers.fetchers.dexscreener import DexscreenerFetcher
1515
from pragma_sdk.common.fetchers.fetchers.pyth import PythFetcher
1616
from pragma_sdk.common.fetchers.fetchers.upbit import UpbitFetcher
17+
from pragma_sdk.common.fetchers.fetchers.bitget import BitgetFetcher
18+
from pragma_sdk.common.fetchers.fetchers.lbank import LbankFetcher
1719

1820
__all__ = [
1921
"BinanceFetcher",
@@ -32,4 +34,6 @@
3234
"DexscreenerFetcher",
3335
"PythFetcher",
3436
"UpbitFetcher",
37+
"BitgetFetcher",
38+
"LbankFetcher",
3539
]
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import asyncio
2+
import time
3+
from typing import List, Optional, Any
4+
5+
from aiohttp import ClientSession
6+
7+
from pragma_sdk.common.configs.asset_config import AssetConfig
8+
from pragma_sdk.common.types.currency import Currency
9+
from pragma_sdk.common.types.pair import Pair
10+
from pragma_sdk.common.types.entry import SpotEntry, Entry
11+
from pragma_sdk.common.exceptions import PublisherFetchError
12+
from pragma_sdk.common.fetchers.interface import FetcherInterfaceT
13+
from pragma_sdk.common.fetchers.handlers.hop_handler import HopHandler
14+
15+
from pragma_sdk.common.logging import get_pragma_sdk_logger
16+
17+
logger = get_pragma_sdk_logger()
18+
19+
# TODO: add exception list
20+
EXCEPTION_LIST: List[Pair] = []
21+
22+
23+
class BitgetFetcher(FetcherInterfaceT):
24+
BASE_URL: str = "https://api.bitget.com/api/v2/spot/market/tickers"
25+
SOURCE: str = "BITGET"
26+
27+
hop_handler = HopHandler(
28+
hopped_currencies={
29+
"USD": "USDT",
30+
}
31+
)
32+
33+
async def fetch_pair(
34+
self, pair: Pair, session: ClientSession, usdt_price: float = 1
35+
) -> Entry | PublisherFetchError:
36+
new_pair = self.hop_handler.get_hop_pair(pair) or pair
37+
url = self.format_url(new_pair)
38+
async with session.get(url) as resp:
39+
if resp.status == 404:
40+
return PublisherFetchError(f"No data found for {pair} from Bitget")
41+
42+
result = await resp.json()
43+
if result["msg"] != "success":
44+
return await self.operate_usdt_hop(pair, session)
45+
return self._construct(pair=pair, result=result, usdt_price=usdt_price)
46+
47+
async def fetch(
48+
self, session: ClientSession
49+
) -> List[Entry | PublisherFetchError | BaseException]:
50+
entries = []
51+
usdt_price = await self.get_stable_price("USDT")
52+
for pair in self.pairs:
53+
if pair not in EXCEPTION_LIST:
54+
entries.append(
55+
asyncio.ensure_future(self.fetch_pair(pair, session, usdt_price))
56+
)
57+
return list(await asyncio.gather(*entries, return_exceptions=True))
58+
59+
def format_url(self, pair: Pair) -> str:
60+
url = f"{self.BASE_URL}?symbol={pair.base_currency.id}{pair.quote_currency.id}"
61+
return url
62+
63+
async def operate_usdt_hop(
64+
self, pair: Pair, session: ClientSession
65+
) -> SpotEntry | PublisherFetchError:
66+
url_pair1 = self.format_url(
67+
Pair(
68+
pair.base_currency,
69+
Currency.from_asset_config(AssetConfig.from_ticker("USDT")),
70+
)
71+
)
72+
async with session.get(url_pair1) as resp:
73+
if resp.status == 404:
74+
return PublisherFetchError(
75+
f"No data found for {pair} from Bitget - hop failed for {pair.base_currency.id}"
76+
)
77+
pair1_usdt = await resp.json()
78+
if "code" in pair1_usdt:
79+
return PublisherFetchError(
80+
f"No data found for {pair} from Bitget - hop failed for {pair.base_currency.id}"
81+
)
82+
83+
url_pair2 = self.format_url(
84+
Pair(
85+
pair.quote_currency,
86+
Currency.from_asset_config(AssetConfig.from_ticker("USDT")),
87+
)
88+
)
89+
async with session.get(url_pair2) as resp:
90+
if resp.status == 404:
91+
return PublisherFetchError(
92+
f"No data found for {pair} from Bitget - hop failed for {pair.quote_currency.id}"
93+
)
94+
pair2_usdt = await resp.json()
95+
if "code" in pair2_usdt:
96+
return PublisherFetchError(
97+
f"No data found for {pair} from Bitget - hop failed for {pair.quote_currency.id}"
98+
)
99+
100+
return self._construct(pair=pair, result=pair2_usdt, hop_result=pair1_usdt)
101+
102+
def _construct(
103+
self,
104+
pair: Pair,
105+
result: Any,
106+
hop_result: Optional[Any] = None,
107+
usdt_price: float = 1,
108+
) -> SpotEntry:
109+
result = result["data"][0]
110+
bid = float(result["bidPr"])
111+
ask = float(result["askPr"])
112+
price = (bid + ask) / (2 * usdt_price)
113+
if hop_result is not None:
114+
hop_bid = float(hop_result["bidPr"])
115+
hop_ask = float(hop_result["askPr"])
116+
hop_price = (hop_bid + hop_ask) / 2
117+
price = hop_price / price
118+
timestamp = int(time.time())
119+
price_int = int(price * (10 ** pair.decimals()))
120+
121+
logger.debug("Fetched price %d for %s from Bitget", price_int, pair)
122+
123+
return SpotEntry(
124+
pair_id=pair.id,
125+
price=price_int,
126+
timestamp=timestamp,
127+
source=self.SOURCE,
128+
publisher=self.publisher,
129+
)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import asyncio
2+
import time
3+
from typing import List, Optional, Any
4+
5+
from aiohttp import ClientSession
6+
7+
from pragma_sdk.common.configs.asset_config import AssetConfig
8+
from pragma_sdk.common.types.currency import Currency
9+
from pragma_sdk.common.types.pair import Pair
10+
from pragma_sdk.common.types.entry import SpotEntry, Entry
11+
from pragma_sdk.common.exceptions import PublisherFetchError
12+
from pragma_sdk.common.fetchers.interface import FetcherInterfaceT
13+
from pragma_sdk.common.fetchers.handlers.hop_handler import HopHandler
14+
15+
from pragma_sdk.common.logging import get_pragma_sdk_logger
16+
17+
logger = get_pragma_sdk_logger()
18+
19+
# TODO: add exception list
20+
EXCEPTION_LIST: List[Pair] = []
21+
22+
23+
class LbankFetcher(FetcherInterfaceT):
24+
BASE_URL: str = "https://api.lbkex.com/v2/supplement/ticker/bookTicker.do"
25+
SOURCE: str = "LBANK"
26+
27+
hop_handler = HopHandler(
28+
hopped_currencies={
29+
"USD": "USDT",
30+
}
31+
)
32+
33+
async def fetch_pair(
34+
self, pair: Pair, session: ClientSession, usdt_price: float = 1
35+
) -> Entry | PublisherFetchError:
36+
new_pair = self.hop_handler.get_hop_pair(pair) or pair
37+
url = self.format_url(new_pair)
38+
async with session.get(url) as resp:
39+
if resp.status == 404:
40+
return PublisherFetchError(f"No data found for {pair} from Lbank")
41+
42+
result = await resp.json()
43+
if result["msg"] != "Success":
44+
return await self.operate_usdt_hop(pair, session)
45+
return self._construct(pair=pair, result=result, usdt_price=usdt_price)
46+
47+
async def fetch(
48+
self, session: ClientSession
49+
) -> List[Entry | PublisherFetchError | BaseException]:
50+
entries = []
51+
usdt_price = await self.get_stable_price("USDT")
52+
for pair in self.pairs:
53+
if pair not in EXCEPTION_LIST:
54+
entries.append(
55+
asyncio.ensure_future(self.fetch_pair(pair, session, usdt_price))
56+
)
57+
return list(await asyncio.gather(*entries, return_exceptions=True))
58+
59+
def format_url(self, pair: Pair) -> str:
60+
url = f"{self.BASE_URL}?symbol={pair.base_currency.id.lower()}_{pair.quote_currency.id.lower()}"
61+
return url
62+
63+
async def operate_usdt_hop(
64+
self, pair: Pair, session: ClientSession
65+
) -> SpotEntry | PublisherFetchError:
66+
url_pair1 = self.format_url(
67+
Pair(
68+
pair.base_currency,
69+
Currency.from_asset_config(AssetConfig.from_ticker("USDT")),
70+
)
71+
)
72+
async with session.get(url_pair1) as resp:
73+
if resp.status == 404:
74+
return PublisherFetchError(
75+
f"No data found for {pair} from Lbank - hop failed for {pair.base_currency.id}"
76+
)
77+
pair1_usdt = await resp.json()
78+
if "code" in pair1_usdt:
79+
return PublisherFetchError(
80+
f"No data found for {pair} from Lbank - hop failed for {pair.base_currency.id}"
81+
)
82+
83+
url_pair2 = self.format_url(
84+
Pair(
85+
pair.quote_currency,
86+
Currency.from_asset_config(AssetConfig.from_ticker("USDT")),
87+
)
88+
)
89+
async with session.get(url_pair2) as resp:
90+
if resp.status == 404:
91+
return PublisherFetchError(
92+
f"No data found for {pair} from Lbank - hop failed for {pair.quote_currency.id}"
93+
)
94+
pair2_usdt = await resp.json()
95+
if "code" in pair2_usdt:
96+
return PublisherFetchError(
97+
f"No data found for {pair} from Lbank - hop failed for {pair.quote_currency.id}"
98+
)
99+
100+
return self._construct(pair=pair, result=pair2_usdt, hop_result=pair1_usdt)
101+
102+
def _construct(
103+
self,
104+
pair: Pair,
105+
result: Any,
106+
hop_result: Optional[Any] = None,
107+
usdt_price: float = 1,
108+
) -> SpotEntry:
109+
result = result["data"]
110+
bid = float(result["bidPrice"])
111+
ask = float(result["askPrice"])
112+
price = (bid + ask) / (2 * usdt_price)
113+
if hop_result is not None:
114+
hop_bid = float(hop_result["bidPrice"])
115+
hop_ask = float(hop_result["askPrice"])
116+
hop_price = (hop_bid + hop_ask) / 2
117+
price = hop_price / price
118+
timestamp = int(time.time())
119+
price_int = int(price * (10 ** pair.decimals()))
120+
121+
logger.debug("Fetched price %d for %s from Lbank", price_int, pair)
122+
123+
return SpotEntry(
124+
pair_id=pair.id,
125+
price=price_int,
126+
timestamp=timestamp,
127+
source=self.SOURCE,
128+
publisher=self.publisher,
129+
)

pragma-sdk/pragma_sdk/supported_assets.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,8 @@
334334
decimals: 5
335335
ticker: 'BONK'
336336
coingecko_id: 'bonk'
337+
338+
- name: 'Dog (Bitcoin)'
339+
decimals: 5
340+
ticker: 'DOG'
341+
coingecko_id: 'dog-go-to-the-moon-rune'
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.5.1"
1+
__version__ = "2.6.0"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.5.1"
1+
__version__ = "2.6.0"

0 commit comments

Comments
 (0)