Создайте простую панель токенов в блокчейне TON с помощью API Stonfi

Любой, кто планировал приобрести токены или другие цифровые активы в блокчейне, столкнулся с трудностью исследования таких активов. Блокчейны плохо приспособлены для сбора аналитики — ноды и лайтноды предоставляют информацию только о конкретном блоке сети, поэтому приходится использовать сервисы индексаторов блокчейна или API сервисов, работающих на блокчейне.

Поскольку децентрализованные биржи стремятся присутствовать на таких платформах, как coingecko, они создают стандартизированные API, часто делая их открытым исходным кодом. Такие API позволяют получить много информации, связанной с торговлей токенами.

Поэтому в этой статье мы соберем дашборд для токенов на блокчейне TON и посмотрим, насколько легко получить данные из DEX, но в конце поговорим о проблемах этого метода сбора данных. Я надеюсь, что такое простое руководство сделает шаги в блокчейне TON понятными и приятными.

Прежде чем мы перейдем к сбору данных, несколько оговорок:

  • код в туториале максимально простой, чтобы его можно было читать по диагонали
  • токены являются стандартом для взаимозаменяемых токенов в TON.

Если вы занимаетесь разработкой на TON вам также может быть полезен наш материал От нуля до героя в экосистеме TON

Вспомогательные функции

Прежде чем вызывать дескриптор API, напишем вспомогательные функции, которые помогут нам с параметрами вызываемых API, а именно определить даты и привести их в нужный нам формат:

def now_utc (): return datetime.datetime.utcnow().strftime( '%Y-%m-%dT%H:%M:%S' ) def тридцати_days_utc (): return (datetime.datetime.utcnow() - datetime.timedelta(days= 30 )).strftime( '%Y-%m-%dT%H:%M:%S' ) def Seven_days_utc (): return (datetime.datetime.utcnow() - datetime.timedelta( days= 7 )).strftime( '%Y-%m-%dT%H:%M:%S' ) def day_utc (): return (datetime.datetime.utcnow() - datetime.timedelta(days= 1 ) ).strftime( '%Y-%m-%dT%H:%M:%S' ) now_utc()

Давайте вызовем API GET https://api.ston.fi/v1/stats/pool .

полезная нагрузка = {'с тех пор': day_utc(), 'до': now_utc()}'с тех пор' : day_utc(), 'до' : now_utc()} r = Requests.get( 'https://api.ston.fi/v1/stats/pool' , params=payload) r.json()[ 'статистика' ][ 0 ]

Давайте получим различные параметры пула:

Теперь попробуем собрать нужную нам информацию

Возьмите поля

Для нашей панели нам понадобится:

  • Имя и символ токена
  • Последняя цена Jetton за выбранный период
  • Объем в тоннах
  • Ссылка на пул обмена

Давайте выберем эти данные с помощью нашего API:

def take_pool_stats (): temp_arr=[] payload = { 'since' : day_utc(), 'until' : now_utc()} # статистика пулов stonfi r = Requests.get( 'https://api.ston.fi/v1 /stats/pool' , params=payload) resp = r.json()[ 'stats' ] для jetton в соотв .: temp_dict = { 'coin' : jetton[ 'base_name' ], 'pair' : jetton[ 'base_symbol' ]+ '/' +jetton[ 'quote_symbol' ], 'url' : jetton[ 'url' ], 'price_ton' : jetton[ 'last_price' ], 'volume_ton' : jetton[ 'quote_volume' ]} temp_arr.append( temp_dict) вернуть temp_arr take_pool_stats()

Мы увидим эти JSON:

```

{'монета': 'Чау-Чау',

'пара': 'ЧАУ/ТОННА',

'url': 'https://app.ston.fi/swap?ft=EQBtWFPgVknfzu6xaVcRBbNP3h_6UJ_xe29sVkiFTyPiv2bq&tt=EQCM3B12QK1e4yZSf8GtBRT0aLMNyEsBc_DhVfRRtOEffLez',

'price_ton': '0,010646867',

'volume_ton': '0.000000000'},

{'монета': 'Тональд Дак',

'пара': 'TDUCK/TON',

'url': 'https://app.ston.fi/swap?ft=EQBUGgcu-h4SqMh5hrentq4vE59tBRRfrYE3H_0s6D_1Xzsa&tt=EQCM3B12QK1e4yZSf8GtBRT0aLMNyEsBc_DhVfRRtOEffLez',

'price_ton': '0,000000363',

'volume_ton': '0.000000000'},

```

Не удивляйтесь, что объём нулевой — создать пул может каждый, поэтому не все они пользуются большим спросом.

Шаг назад

Неудобно смотреть цены в TON, поэтому для представления цен в долларах мы получим текущее значение TON/USD. Для этого мы будем использовать для нашей задачи tonapi.io, бесплатных лимитов вполне достаточно:

def take_ton_price (): resp = Requests.get( 'https://tonapi.io/v2/rates?tokens=ton¤cy=usd' ) # Пример: {"rates":{"TON":{"prices":{ "USD":2.1215},"diff_24h":{"USD":"+0.85%"},"diff_7d":{"USD":"-6.04%"},"diff_30d":{"USD":"+ 2,75%"}}}} return resp.json()[ "rates" ][ "TON" ][ "prices" ][ "USD" ] take_ton_price()

Давайте удалим ненужное

Мы используем полученный обменный курс для пересчета объема и цены. Как уже говорилось выше, мы отдаем все пулы в API, это значит, что туда могут попасть невостребованные пулы, объем которых равен нулю. А также пулы между токенами, которые нам не интересны, так как не отображают цену и объем торгов относительно TON или доллара. Соответственно:

  • выбирайте пулы с TON
  • мы удалим пулы, в которых последняя цена равна нулю
  • мы удалим пулы, в которых объем торгов за период меньше $1000

И сразу сортируем по объему:

def take_pool_stats (): temp_arr=[] payload = { 'since' : day_utc(), 'until' : now_utc()} # статистика пулов stonfi r = Requests.get( 'https://api.ston.fi/v1 /stats/pool' , params=payload) resp = r.json()[ 'stats' ] # ton_usd ton_usd = take_ton_price() для jetton в соотв .: temp_dict = { 'coin' : jetton[ 'base_name' ], 'pair ' : jetton[ 'base_symbol' ]+ '/' +jetton[ 'quote_symbol' ], 'url' : jetton[ 'url' ], 'price_ton' : jetton[ 'last_price' ], 'volume_ton' : jetton[ 'quote_volume ' ], 'price_usd' : round ( float (jetton[ 'last_price' ])*ton_usd, 2 ), 'volume_usd' : round ( float (jetton[ 'quote_volume' ])*ton_usd, 2 )} if (jetton[ ' quote_symbol' ]== 'TON' и int ( float (jetton[ 'last_price' ]) != 0 ) и int ( float (jetton[ 'quote_volume' ]) != 0 ) и int (temp_dict[ 'volume_usd' ]) > 1000 ): temp_arr.append(temp_dict) return sorted (temp_arr, key= лямбда d: d[ 'volume_usd' ],reverse= True ) # Coin - base_name # Пара - base_symbol/quote_symbol url # Цена - Last_price * TON в долларах США цена # 24 Объем - непонятно чекнуть по coingecko take_pool_stats()

В результате мы получим такой json:

```

{'монета': 'СТОН',

'пара': 'СТОН/ТОН',

'url': 'https://app.ston.fi/swap?ft=EQA2kCVNwVsil2EM2mB0SkXytxCqQjS4mttjDpnXmwG9T6bO&tt=EQCM3B12QK1e4yZSf8GtBRT0aLMNyEsBc_DhVfRRtOEffLez',

'price_ton': '2.220362684',

'volume_ton': '74651.187439449',

'price_usd': 5,89,

'volume_usd': 197926,43},

```

Процент от общего числа

Объем удобно считать от общего объема на рынке, поэтому посчитаем объем объема и добавим процент. (В коде видно, что я оставил целых 10 цифр после запятой, это связано с тем, что TON недавно взял на себя инициативу по добавлению ликвидности в пулы, из-за чего объемы были сильно «размыты». В обычной ситуации 4-х символов было бы достаточно)

def take_pool_stats ( payloa ): temp_arr=[] # статистика пулов stonfi r = Requests.get( 'https://api.ston.fi/v1/stats/pool' , params=payload) resp = r.json()[ 'stats' ] # ton_usd ton_usd = take_ton_price() # для процента объема all_volume = sum ( float (item[ 'quote_volume' ]) для элемента в соотв.) print (all_volume) для jetton в соотв.: temp_dict = { 'coin' : jetton [ 'base_name' ], 'pair' : jetton[ 'base_symbol' ]+ '/' +jetton[ 'quote_symbol' ], 'url' : jetton[ 'url' ], 'price_ton' : jetton[ 'last_price' ], 'volume_ton' : jetton[ 'quote_volume' ], 'price_usd' : round ( float (jetton[ 'last_price' ])*ton_usd, 4 ), 'volume_usd' : round ( float (jetton[ 'quote_volume' ])*ton_usd, 2 ), "volume_perc" : round (( float (jetton[ 'quote_volume' ])/all_volume)* 100 , 10 )} if (jetton[ 'quote_symbol' ]== 'TON' и int ( float (jetton[ 'last_price ' ]) != 0 ) и int ( float (jetton[ 'quote_volume' ]) != 0 ) и int (temp_dict[ 'volume_usd' ]) > 1000 ): temp_arr.append(temp_dict) возвращает отсортированный (temp_arr, key= лямбда d: d[ 'volume_usd' ],reverse= True ) payload = { 'since' : day_utc(), 'until' : now_utc()} take_pool_stats(payload)

Поместим полученный список в фрейм данных библиотеки Pandas для удобства отображения и получим:

На таком простом примере вы можете проверить свои гипотезы, связанные с токенами, например, посмотрев динамику за несколько дней или рассмотрев разные периоды. Но практически любое исследование приводит к необходимости получения подробной информации о пулах. Ведь совершенно понятно, что с пары кошельков можно увеличить объем, ускорив тем самым работу токена. Для этого необходимо собрать информацию об операциях.

Сбор информации по операциям

API StoneFi имеет отдельный метод, возвращающий операции. Удобно, что для каждой операции прописан пул, в котором операция была выполнена. Мы воспользуемся этим, чтобы подсчитать количество свопов по пулам и посмотреть, сколько уникальных кошельков входит в число этих операций.

Для начала получим операции за период:

def take_operations ( полезная нагрузка ): r = Requests.get( 'https://api.ston.fi/v1/stats/operations' , params=payload) return r.json()[ "operations" ]

Операции в пулах разные, есть свопы, когда пользователи обменивают токены и TON, есть добавление ликвидности в пулы, возможные операции могут отличаться от биржи к бирже. В нашем простом примере мы будем использовать только свопы.

Давайте соберем функцию, которая для каждого выбранного нами пула будет возвращать количество свопов и количество уникальных кошельков, совершивших эти свопы.

def count_pool_operations ( operations,addr_str ): pool_oper_list = list ( filter ( лямбда person: person[ 'operation' ][ 'pool_address' ] == addr_str, Operations)) unique_counts = Collections.Counter(e[ 'operation' ][ 'destination_wallet_address ' ] for e в пул_oper_list) return len (pool_oper_list), len ( set (unique_counts))

Добавим эту информацию на дашборд:

temp_arr=[] # статистика пулов stonfi# статистика пулов stonfi r = Requests.get( 'https://api.ston.fi/v1/stats/pool' , params=payload) resp = r.json()[ 'stats' ] # ton_usd ton_usd = take_ton_price( ) # для процента объема all_volume = sum ( float (item[ 'quote_volume' ]) для элемента в соотв.) # Take Operations Payload[ 'op_type' ] = 'Swap' Operations = take_operations(payload) для Jetton в соотв.: temp_dict = { 'pool_address' : jetton[ 'pool_address' ], 'coin' : jetton[ 'base_name' ], 'pair' : jetton[ 'base_symbol' ]+ '/' +jetton[ 'quote_symbol' ], 'url' : jetton[ 'url' ], 'price_ton' : jetton[ 'last_price' ], 'volume_ton' : jetton[ 'quote_volume' ], 'price_usd' : round ( float (jetton[ 'last_price' ])*ton_usd, 4 ), 'volume_usd ' : round ( float (jetton[ 'quote_volume' ])*ton_usd, 2 ), "volume_perc" : round (( float (jetton[ 'quote_volume' ])/all_volume)* 100 , 2 )} #temp_dict = {'coin ': jetton['base_name'],'pair': jetton['base_symbol']+'/'+jetton['quote_symbol'],'url': jetton['url'],'price_ton': jetton['last_price '],'volume_ton': jetton['quote_volume'], 'price_usd': round(float(jetton['last_price'])*ton_usd,2),'volume_usd': round(float(jetton['quote_volume']) *ton_usd,2)} #temp_dict = {'coin': jetton['base_name'],'pair': jetton['base_symbol']+'/'+jetton['quote_symbol'],'url': jetton[' url'],'price_ton': jetton['last_price'],'volume_ton': jetton['quote_volume'], 'price_usd': jetton['last_price'],'volume_usd':jetton['quote_volume']} if (jetton[ 'quote_symbol' ]== 'TON' и int ( float (jetton[ 'last_price' ]) != 0 ) и int ( float (jetton[ 'quote_volume' ]) != 0 ) и int (temp_dict[ 'volume_usd' ]) > 1000 ): temp_pool_count = count_pool_operations(operations,temp_dict[ 'pool_address' ]) temp_dict[ "count_swaps" ] = temp_pool_count[ 0 ] temp_dict[ "count_unique" ] = temp_pool_count[ 1 ] temp_arr. add(temp_dict) return sorted (temp_arr, key= лямбда d: d[ 'volume_usd' ],reverse= True ) # Coin - base_name # Пара - base_symbol/quote_symbol url # Price - Last_price * TON в долларах США цена # 24 Объем - нет понятно чекнуть по coingecko payload = { 'since' : day_utc(), 'until' : now_utc()} take_pool_stats(payload) import pandas as pd df = pd.DataFrame(take_pool_stats(payload))

Результат:

Ложка дегтя

Пример, который мы собрали выше, показывает, насколько легко собирать данные о пулах и операциях, но есть и проблемы.

Так как задача API — предоставление статистических данных, то исходя из цены токенов мы получаем последнюю цену за период, что не очень корректно с аналитической точки зрения. Поэтому, если для нас важна цена токена за период, важно будет рассчитать взвешенную по времени цену, что приведет к увеличению количества запросов к API.

Вторая проблема такого сбора данных — время, необходимое для выполнения одного запроса; API децентрализованных бирж не адаптированы для глубоких запросов, поэтому если вас интересует какая-то живая аналитика, то единственный выход — собирать данные напрямую из смарт-контрактов — вызов методов get.

Заключение

Мне нравится блокчейн TON за его техническую элегантность; по крайней мере это не очередная копия Эфириума, которую разгоняют с помощью большого капитала без оглядки и вообще зачем это нужно пользователю. Если вы хотите узнать больше о блокчейне TON, у меня есть уроки с открытым исходным кодом, которые научат вас создавать полноценные приложения на TON.

Новые руководства и аналитика данных от автора статьм здесь.

TonUP (На тон выше) - фундаментальный разбор монет и зарабаток на AirDrop-ах. TradingUP - сигналы и торговые стратегии. Покупаю криптовалюту на ByBit | MEXC | CryptoBot.

От нуля до героя в экосистеме TON: cмарт-контракты, инструменты разработки, примеры, лаунчпад в экосистеме
Где в мире Сатоши Накамото?

Биткойн — это обширная и невероятная история, а загадка личности создателя добавляет еще больше волнения. Следуйте за нами в этом путешествии по поиску информации о личности самого неуловимого человека в истории, Сатоши Накамото.

0
Комментарии
-3 комментариев
Раскрывать всегда