使用 Stonfi API 在 TON 区块链上创建一个简单的代币仪表盘
任何计划在区块链上购买代币或其他数字资产的人都会遇到研究此类资产的难题。区块链并不适合收集分析数据——节点和轻节点仅提供网络特定区块的信息,因此您必须使用区块链索引服务或运行在区块链上的服务的 API。
为了在 CoinGecko 等平台上占据一席之地,去中心化交易所纷纷创建标准化 API,并且通常会将其开源。这些 API 使用户能够获取大量与代币交易相关的信息。
因此,在本文中,我们将搭建一个 TON 区块链代币仪表盘,并展示如何轻松地从去中心化交易所 (DEX) 获取数据。但最后,我们将探讨这种数据收集方法存在的问题。我希望这篇简单的教程能够让您清晰愉快地了解 TON 区块链的运作步骤。
在开始数据收集之前,先做几点说明:
教程中的代码尽可能简洁,以便可以从对角线方向阅读
。Tokens 是 TON 上可互换代币的标准。
辅助函数
在调用 API 句柄之前,让我们编写一些辅助函数来帮助我们处理被调用 API 的参数,即确定日期并将其转换为我们需要的格式:
def now_utc():
return datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
def thirty_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
payload = {'since': day_utc(), 'until': now_utc()}
r = requests.get('https://api.ston.fi/v1/stats/pool', params=payload)
r.json()['stats'][0]
让我们获取各种池参数:
现在让我们尝试收集我们需要的信息。
拿场
我们的仪表盘需要以下信息:
代币名称和符号、
所选时间段内的最新 Jetton 价格、
TON
交易量、交易池链接
让我们使用 API 选择这些数据:
def take_pool_stats():
temp_arr=[]
payload = {'since': day_utc(), 'until': now_utc()}
# stonfi pools stats
r = requests.get('https://api.ston.fi/v1/stats/pool', params=payload)
resp = r.json()['stats']
for jetton in resp:
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)
return temp_arr
take_pool_stats()
我们将看到以下JSON数据:
{'coin': 'Chow Chow',
'pair': 'CHOW/TON',
'url': 'https://app.ston.fi/swap?ft=EQBtWFPgVknfzu6xaVcRBbNP3h_6UJ_xe29sVkiFTyPiv2bq&tt=EQCM3B12QK1e4yZSf8GtBRT0aLMNyEsBc_DhVfRRtOEffLez',
'price_ton': '0.010646867',
'volume_ton': '0.000000000'},
{'coin': 'Tonald Duck',
'pair': '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/USD 的当前汇率。为此,我们将使用 tonapi.io,免费额度已经足够用了:
def take_ton_price():
resp = requests.get('https://tonapi.io/v2/rates?tokens=ton¤cies=usd')
# Ex: {"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 pools stats
r = requests.get('https://api.ston.fi/v1/stats/pool', params=payload)
resp = r.json()['stats']
# ton_usd
ton_usd = take_ton_price()
for jetton in resp:
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' and int(float(jetton['last_price']) != 0) and int(float(jetton['quote_volume']) != 0) and int(temp_dict['volume_usd']) > 1000):
temp_arr.append(temp_dict)
return sorted(temp_arr, key=lambda d: d['volume_usd'],reverse=True)
# Coin - base_name
# Pair - base_symbol/quote_symbol url
# Price - last_price * TON in USD price
take_pool_stats()
结果我们得到如下 JSON 数据:
{'coin': 'STON',
'pair': 'STON/TON',
'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位就足够了。)
。
# Percentage from total
def take_pool_stats(payloa):
temp_arr=[]
# stonfi pools stats
r = requests.get('https://api.ston.fi/v1/stats/pool', params=payload)
resp = r.json()['stats']
# ton_usd
ton_usd = take_ton_price()
# for volume percentage
all_volume = sum(float(item['quote_volume']) for item in resp)
for jetton in resp:
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' and int(float(jetton['last_price']) != 0) and int(float(jetton['quote_volume']) != 0) and int(temp_dict['volume_usd']) > 1000):
temp_arr.append(temp_dict)
return sorted(temp_arr, key=lambda d: d['volume_usd'],reverse=True)
payload = {'since': day_utc(), 'until': now_utc()}
take_pool_stats(payload)
为了方便显示,我们将结果列表放入 Pandas 库的数据框中,得到:
通过这样简单的例子,你可以检验与代币相关的假设,例如,观察几天内的动态变化或考虑不同的时间段。但几乎所有研究最终都需要关于资金池的详细信息。毕竟,很明显,你可以通过几个钱包增加交易量,从而加速代币的上涨。为此,你需要收集有关交易操作的信息。
收集有关行动的信息
StoneFi API 有一个单独的方法返回操作信息。方便的是,每次操作都会记录执行该操作的资金池。我们将利用这一点来统计每个资金池的兑换次数,并查看这些操作涉及多少个不同的钱包。
首先,我们来获取该期间的运营情况:
def take_operations(payload):
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(lambda person: person['operation']['pool_address'] == addr_str, operations))
unique_counts = collections.Counter(e['operation']['destination_wallet_address'] for e in pool_oper_list )
return len(pool_oper_list),len(set(unique_counts))
让我们把这些信息添加到仪表盘中:
def take_pool_stats(payload):
temp_arr=[]
# stonfi pools stats
r = requests.get('https://api.ston.fi/v1/stats/pool', params=payload)
resp = r.json()['stats']
# ton_usd
ton_usd = take_ton_price()
# for volume percentage
all_volume = sum(float(item['quote_volume']) for item in resp)
# take operations
payload['op_type'] = 'Swap'
operations = take_operations(payload)
for jetton in resp:
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)}
if(jetton['quote_symbol']=='TON' and int(float(jetton['last_price']) != 0) and int(float(jetton['quote_volume']) != 0) and 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.append(temp_dict)
return sorted(temp_arr, key=lambda d: d['volume_usd'],reverse=True)
payload = {'since': day_utc(), 'until': now_utc()}
df = pd.DataFrame(take_pool_stats(payload))
结果:
一勺焦油
我们上面收集的例子展示了收集关于资金池和操作的数据是多么容易,但也存在一些问题。
由于 API 的任务是提供统计数据,基于代币价格,我们只能获得该时间段内的最新价格,从分析的角度来看,这并不十分准确。因此,如果我们需要了解某个时间段内代币的价格,就必须计算时间加权价格,但这会导致 API 请求次数的增加。
这种数据收集方式的第二个问题是完成单个请求所需的时间;去中心化交易所的 API 并不支持深度查询,因此,如果您对某种实时分析感兴趣,那么唯一的办法就是直接从智能合约中收集数据——调用 GET 方法。
结论
我喜欢TON区块链的技术精妙之处;至少它不是以太坊的翻版,以太坊在大量资金的推动下盲目超频,完全不顾及用户的实际需求。如果你想了解更多关于TON区块链的信息,我有一些开源课程,可以教你如何在TON上创建功能齐全的应用程序。
https://github.com/romanovichim/TonFunClessons_Eng
我会在这里发布新的教程和数据分析:
文章来源:https://dev.to/roma_i_m/create-a-simple-dashboard-of-tokens-on-ton-blockchain-using-the-stonfi-api-55ek


