我正试图使用web3.py和Uniswap对合约来计算Uniswap中代币的价格,但我一定在数学上做错了什么。示例:我想计算一个以美元计价的ETH的价格。我首先连接到配对合约USDC/ETH(0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc(,通过web3.py访问智能合约功能。
如本文所述(https://uniswap.org/docs/v2/smart-contract-integration/building-an-oracle/)我将price1CumulativeLast()
的结果和相关的时间戳存储在两个不同的时间点(每个函数调用之间一分钟(。然后我使用公式
(price0CumulativeLATEST--price0CsumulativeFIRST(/(时间戳OfLATEST--时间戳(FIRST(
(请参阅:https://medium.com/@epeph/using-uniswap-v2-oracle-with-storage-proofs-350e699e1d3(来计算以代币0(USDC(计价的代币1(ETH(的价格。
Uniswap文档说price1CumulativeLast((返回一个Q112Q112固定点号,这就是为什么我认为我无法理解这些数字。
我曾尝试搜索Python函数,以轻松地将定点Q112Q112转换为浮点,但还没有找到有效的解决方案,所以我想我一定在以太坊智能合约或Uniswap中使用的数学或单位方面出了根本性的问题。
def calculate_price():
'''
Call price1CumulativeLast() three times with one minute interval between each call.
'''
results = []
for x in range(3):
try:
temp_dict = {}
start_ts = w3.eth.getBlock(w3.eth.block_number).timestamp
token1_price_start = contract.functions.price1CumulativeLast().call()
time.sleep(60*1)
end_ts = w3.eth.getBlock(w3.eth.block_number).timestamp
token1_price_end = contract.functions.price1CumulativeLast().call()
temp_dict['start_ts'] = start_ts
temp_dict['token1_price_start'] = token1_price_start
temp_dict['end_ts'] = end_ts
temp_dict['token1_price_end'] = token1_price_end
results.append(temp_dict)
except:
continue
return results
这给了我:
results = [{'start_ts': 1623002172,
'token1_price_start': 183015811459414492033193017518027,
'end_ts': 1623002242,
'token1_price_end': 183016664977333417354464783721666},
{'start_ts': 1623002242,
'token1_price_start': 183016664977333417354464783721666,
'end_ts': 1623002250,
'token1_price_end': 183016664977333417354464783721666},
{'start_ts': 1623002250,
'token1_price_start': 183016664977333417354464783721666,
'end_ts': 1623002355,
'token1_price_end': 183018525945544514538790080485913}]
我现在在公式中插入两个时间戳和两个价格,以在一分钟的时间间隔内重新计算以token0计价的token1的价格:
price = (results[0]['token1_price_end'] - results[0]['token1_price_start']) / (results[0]['end_ts'] - results[0]['start_ts'])
format(price, '.10f')
这将返回以下字符串:
'12193113127504589866663936.0000000000'
在撰写本文时,这个数字应该在2800左右(1 ETH=2800 USDC(,但我不知道如何从这里得到这个数字。我做错了什么?
这里有一个示例代码,它使用web3以太坊defi库以几种方式计算Uniswap对合同价格。
我认为price1CumulativeLast
不需要参与。
示例代码
-
使用Uniswap v2对
reserve0
和reserve1
获取价格条目 -
最新交易后的价格
-
时间加权平均价格
"""Show live BNB/BUSD price from PancakeSwap pool.
- Show the latest price
- Show the TWAP price
Also
- Uses HTTP polling method
- Adjusts for minor chain reorgs / unstable chain tip
To run:
.. code-block:: python
export BNB_CHAIN_JSON_RPC="https://bsc-dataseed.binance.org/"
python scripts/live-price.py
"""
import datetime
import os
import time
from web3 import Web3, HTTPProvider
from web3.middleware import geth_poa_middleware
from eth_defi.price_oracle.oracle import PriceOracle, time_weighted_average_price
from eth_defi.uniswap_v2.oracle import update_live_price_feed
from eth_defi.uniswap_v2.pair import fetch_pair_details
def main():
json_rpc_url = os.environ["BNB_CHAIN_JSON_RPC"]
web3 = Web3(HTTPProvider(json_rpc_url))
web3.middleware_onion.clear()
web3.middleware_onion.inject(geth_poa_middleware, layer=0)
# https://tradingstrategy.ai/trading-view/binance/pancakeswap-v2/bnb-busd
pair_contract_address = "0x58F876857a02D6762E0101bb5C46A8c1ED44Dc16"
reverse_token_order = False
pair_details = fetch_pair_details(web3, pair_contract_address)
print(f"Displaying live and TWAP price for {pair_details.token0.symbol} - {pair_details.token1.symbol}")
price_ticker = f"{pair_details.token0.symbol}/{pair_details.token1.symbol}"
oracle = PriceOracle(
time_weighted_average_price,
max_age=datetime.timedelta(minutes=15), # Crash if we data gets more stale than 15 minutes
min_duration=datetime.timedelta(minutes=1),
)
# How fast BNB Smart chain ticks
block_time = 3.0
initial_fetch_safety_margin = 1.2
# To back fill the oracle buffer,
# unitially fetch data for the latest time window blocks plus 20% safety margin
initial_fetch_block_count = int(oracle.target_time_window / datetime.timedelta(seconds=block_time) * initial_fetch_safety_margin)
print(f"Starting initial data fetch of {initial_fetch_block_count} blocks")
update_live_price_feed(
oracle,
web3,
pair_contract_address,
reverse_token_order=reverse_token_order,
lookback_block_count=initial_fetch_block_count)
print(f"Starting live price feed, TWAP time window is set to {oracle.target_time_window}")
while True:
stats = update_live_price_feed(
oracle,
web3,
pair_contract_address,
reverse_token_order=reverse_token_order)
last_price = oracle.get_newest().price
twap = oracle.calculate_price()
oldest = oracle.get_oldest()
newest = oracle.get_newest()
print(f"Block {oracle.last_refreshed_block_number:,} at {oracle.last_refreshed_at} current price:{last_price:.4f} {price_ticker} TWAP:{twap:.4f} {price_ticker}")
print(f" Oracle data updates: {stats}, trades in TWAP buffer:{len(oracle.buffer)}, oldest:{oldest.timestamp}, newest:{newest.timestamp} ")
time.sleep(block_time)
if __name__ == "__main__":
main()
有关更多信息,请参阅此处。