A Personal Account of Fully On-Chain Trading Strategy Implementation
As a researcher, I have conducted extensive research on the APIs and SDKs of numerous Web3 projects. Although I routinely test the technical stack during my research, the truth is that if my focus is only restricted to ‘test’, most of the tools and interfaces are great. Passing a functionality test is the basic requirement of any tool, yet in real-life scenarios, simply working is often insufficient. Moreover, this experience has underscored that the role of developer is irreplaceable in any project, even in the era of artificial intelligence.
My task is straightforward. I aim to retrieve all the latest prices from all the on-chain markets for a token that lacks liquidity. Subsequently, I will determine the most effective route to implement my trading strategy.
When trading an asset with abundant liquidity, I do not have much to worry about. In such cases, I have numerous options, including trading on DEXs or CEXs, and given the modest volume of my transactions, I can expect a consistent and acceptable price across platforms.
However, the issue arises when the token’s existing liquidity pool is very small. Direct swapping would result in an unfavorable price, rendering my trading strategy ineffective. Therefore, my initial task is to split my transactions into smaller amounts and route them efficiently.
So, how can I ensure that I trade via the most efficient route? I need to access real-time price data of all the pools. You might suggest using oracles to fetch these data. This was also my initial thought. However, after experimenting with well-known oracles like Chainlink, Pyth, and DIA, I decided to fetch the price data directly from the pools’ smart contracts instead. Why? Because I discovered that most oracles do not offer price data for less popular assets and, even when they do, they may not account for all liquidity pools. Often, for convenience, they only retrieve prices from Uniswap. I began to wonder: if oracles can fetch data from smart contracts, why can’t I? At least on blockchain, I am on equal footing with other oracle solutions. The speed at which they update on-chain data is also limited by the block generation time(e.g. 15 seconds on Ethereum). Furthermore, reading data on-chain is straightforward; you simply need a Web3 provider API like Alchemy.
Now, my task has become clearer. I simply need to access all the pools’ on-chain price data to identify the optimal venue for executing my trading strategy. However, this task is not as easy as it sounds. First, I must identify all the pools that trade this token.
If you are a developer from traditional financial markets, you might not see this as a problem. In traditional markets, there are only a few exchanges, even including the OTC trading. However, the blockchain world is entirely different. Trading pools are not as obvious or easily accessible as those in traditional markets. Firstly, numerous blockchains exist, and a token may be listed on nearly all of them. Secondly, each blockchain hosts multiple decentralized exchanges, specifically automated market makers(AMMs). Even within the same DEX, a single token can have many different trading pairs. Furthermore, even the same trading pair can be found in different pools with varying fee tiers. However, because the token I intend to trade lacks liquidity, it isn’t available in as many pools as popular assets like WETH and WBTC; still, it is traded on a significant number of DEXs - seven in my case.
To ensure I’ve covered all the liquidity pools the token trades in, I trace back to its initial minting transaction and filter out all subsequent transactions it has undergone. Since the action of adding liquidity is quite distinct, I simply identify and mark all the liquidity pools in this manner. The only tool I need is Etherscan API.
Now that we have fetched the price data from all the on-chain pools. After some strategic calculations in the backend, it’s time to implement my trading strategy. Specifically, this involves buying some tokens at some locations and selling them at others. There are two types of on-chain trading. The first is order book trading, similar to that found in traditional markets. The second type is AMM trading. This method involves trading with a liquidity-staked pool, where the price is influenced by the trading volume relative to the pool’s total volume. In theory, both trading methods can be executed in a fully automated manner. Orderbook trading platforms provide APIs to place and cancel orders. AMM smart contracts inherently provide interfaces, as they are deployed on the blockchain.
I’ve found that, in my scenario, prices in an orderbook market are more favorable than those in AMM most of the time. Consequently, I decided to use the sdk of that project. However, I discovered three different versions of the SDK simultaneously. These versions have similar names but differ slightly in their logic. After several trials, I found that none of them work perfectly. One had a deprecated dependency, requiring me to rewrite some of the logic within the SDK to use it. Another was not compatible with the existing API. The last one only supports placing orders and does not offer functions to cancel them, which left my strategy incomplete. Ironically, after exploring various methods to place orders, I opted to do so manually, as my scenario does not involve frequent price changes.
Having been immersed in the Web3 space for many years, I have encountered hundreds of trading solutions. Most of them boast about their superiority over older tools and the easy, fast experience they provide. However, my experience with fully on-chain trading has led me to conclude that existing solutions are far from reliable and mature. Only through hands-on practice have I realized how fragile and limited the current technical stack in this field is. This also suggests significant room for improvement and substantial opportunities for proactive innovators.
Last updated