-
-
Save Valian/d16ef72a0e17ee82c0acf606d6a744d7 to your computer and use it in GitHub Desktop.
from collections import defaultdict | |
from operator import itemgetter | |
from time import time | |
from binance.client import Client | |
FEE = 0.0005 | |
PRIMARY = ['ETH', 'USDT', 'BTC', 'BNB'] | |
def main(): | |
start_time = time() | |
prices = get_prices() | |
prices_time = time() | |
print(f"Downloaded in: {prices_time - start_time:.4f}s") | |
triangles = list(find_triangles(prices)) | |
print(f"Computed in: {time() - prices_time:.4f}s") | |
if triangles: | |
for triangle in sorted(triangles, key=itemgetter('profit'), reverse=True): | |
describe_triangle(prices, triangle) | |
else: | |
print("No triangles found, try again!") | |
def get_prices(): | |
client = Client(None, None) | |
prices = client.get_orderbook_tickers() | |
prepared = defaultdict(dict) | |
for ticker in prices: | |
pair = ticker['symbol'] | |
ask = float(ticker['askPrice']) | |
bid = float(ticker['bidPrice']) | |
for primary in PRIMARY: | |
if pair.endswith(primary): | |
secondary = pair[:-len(primary)] | |
prepared[primary][secondary] = 1 / ask | |
prepared[secondary][primary] = bid | |
return prepared | |
def find_triangles(prices): | |
triangles = [] | |
starting_coin = 'BTC' | |
for triangle in recurse_triangle(prices, starting_coin, starting_coin): | |
coins = set(triangle['coins']) | |
if not any(prev_triangle == coins for prev_triangle in triangles): | |
yield triangle | |
triangles.append(coins) | |
def recurse_triangle(prices, current_coin, starting_coin, depth_left=3, amount=1.0): | |
if depth_left > 0: | |
pairs = prices[current_coin] | |
for coin, price in pairs.items(): | |
new_price = (amount * price) * (1.0 - FEE) | |
for triangle in recurse_triangle(prices, coin, starting_coin, depth_left - 1, new_price): | |
triangle['coins'] = triangle['coins'] + [current_coin] | |
yield triangle | |
elif current_coin == starting_coin and amount > 1.0: | |
yield { | |
'coins': [current_coin], | |
'profit': amount | |
} | |
def describe_triangle(prices, triangle): | |
coins = triangle['coins'] | |
price_percentage = (triangle['profit'] - 1.0) * 100 | |
print(f"{'->'.join(coins):26} {round(price_percentage, 4):-7}% <- profit!") | |
for i in range(len(coins) - 1): | |
first = coins[i] | |
second = coins[i + 1] | |
print(f" {second:4} / {first:4}: {prices[first][second]:-17.8f}") | |
print('') | |
if __name__ == '__main__': | |
main() |
Pulling data in: 0.2061s Transforming data in: 0.2649s Find opportunities in: 0.0702s
Time to receive data from API is decent (200ms) and to process data for too (70ms), however transforming pulled data into dictionnary is quite long (260ms). Maybe a way to make this step more efficient could make those opportunities tradable ?
Latency for trading via API is usually around 200ms.
Trying to optimize data transformation part might worth a shot ?
actually if you put your bot to amazon tokyo instance you will get 10 ms for api response. Should be enough for triarb
Also you should check orderbook for big txamounts, good luck
Hi Valian
I have an error trying to run your script, I wonder if you would kindly be able to advise what the likely reason for this is please - many thanks - obviously I did modify the script to add my api keys.
root@Ubuntu-1804-bionic-64-minimal /opt/TrangularArbitrage # python triangular_arbitrage.py
Traceback (most recent call last):
File "triangular_arbitrage.py", line 80, in
main()
File "triangular_arbitrage.py", line 13, in main
prices = get_prices()
File "triangular_arbitrage.py", line 38, in get_prices
prepared[primary][secondary] = 1 / ask
ZeroDivisionError: float division by zero
@Tilanthi @GRTTX just means that there aren't ask prices on the current ticker, just add:
if ask == 0.0:
continue
before the for loop
I am looking into arbitrage also on Binance but the problem is the precision of your amount to put in the orderbook, it's not always precision 8, for example BNB trade at 3 places after the comma, so if your first leg of the arbitrage buys bnb's for usdt then you have perhaps 2.8647899 bnb but if you place an order you must stay with precision three so this amount becomes a rounddown to 2.864 instead of rouding up to 2.865, so you already have some leftover bnb coins in your account like 0.0007899 bnb OR you must with every coin you look at for arbitrage do a roudup but that means for every 'crap' coin you must buy some and sell after so that you have some 'leftovers'. Sometimes you have an arbitrage of > 0.00225 percent (the fees for Binance) BUT if you then actually take a wager amount to start from and you have to do the Rounddown in step 2 and also sometimes on step 3 (depends on the situation bidaskbid-askaskbid-bidbidask etc..). My opinion is that these roudndown make it even harder to do the placeing of orders in reality... If someone has another opinion on that matter or a solution please let me know!!!
Binance 'Taker' (limit order) fees (currently) are 0.00075 rather than 0.0005, this is a significant difference, even at VIP1 level the fee is 0.000675. Besides this it's impossible to know how long a specific arbitrage opportunity will remain open. With API latency of 500ms this means the window would be approx. 2secs and it's clear that most of the arbitrage openings identified do not last this long.
FEE = 0.0075
Hey alissonf216 - thanks for the comment correcting @uk ... 's fee figure (which I think was meant to be percentage). But essentially for the retail trader, tri-arb has not really been a profitable strategy for the last few years - most retail traders do not have access to sufficiently optimised low latency configurations, and the available liquidity on most of the exchanges that have low enough fees to allow any possibility of profit is usually too low to guarantee closure of a triangular loop, with the consequence that the trader builds up a substantial 'bank' of intermediate coins where the tri-arbitrage loop has not closed. This strategy was 'fun' many years ago, but with the aggressive front-running bots now active on most exchanges (perhaps even 'zero-latency' ones co-located within the exchange racks) it is not worth wasting time with, apart from if you want a flutter for a bit of crypto fun. There are possibilities if you understand how to build things, in quad arbitrage - but it is a much slower kind of arbitrage strategy, and the available profitable windows tend to only last for short periods of time (sometimes as much as a few 10's of minutes a day) before they close - so again, not really suitable for the average retail trader, and requires simultaneously running a simulator to determine the short periods when a given market quadruplet is in a profitable situation. There are much easier ways these days to make money with automated trading bots, and in my view you would have to be a true tri-arb aficionado to expect this kind of strategy to produce any significant profit. Perhaps someone will jump in here and tell us all that they are making mega squillions of dollars a year with tri-arb - but I would be surprised should this prove to be the case !
This is working?