Сейчас на слуху криптовалюты, появилось огромное количество бирж. Исходя из предположения, что на разнице курсов на разных биржах, можно заработать, решил изучить возможность создания арбитражного робота. А в основном, чтобы начать изучать python на реальном примере. Итак, приступим.
В первую очередь требуется обнаружить валютные пары, по которым возможна арбитражная торговля. Нам нужны пары, у которых в первом приближении, идет активная торговля, и цены на разных биржах расходятся и сходятся.
Навскидку план работы должен быть такой:
- Создание базы данных, где будут храниться цены валютных пар.
- Сервер который будет сохранять данные в базу.
- Первичный анализ.
Исходники доступны по ссылке arb_analysis.
Создание базы данных
Для того чтобы хранить данные, понадобится 3 таблицы.
В этой таблице будет храниться список бирж.
CREATE TABLE `exchange` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM;
Список криптовалютных пар.
CREATE TABLE `market` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(50) NOT NULL,
`id_exchange` int(11) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM;
CREATE INDEX id_exchange ON market (id_exchange);
Таблица со сделками, также здесь будет храниться информация, по данным из биржевого стакана.
CREATE TABLE `ticker` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_market` int(5) NOT NULL,
`local_time` int(9) NOT NULL,
`timestamp` int(9) NOT NULL,
`last` DECIMAL (11,11) NOT NULL,
`low` DECIMAL (11,11),
`high` DECIMAL (11,11),
`bid` DECIMAL (11,11),
`ask` DECIMAL (11,11),
PRIMARY KEY (id)
) ENGINE=MyISAM;
CREATE INDEX id_market ON ticker (id_market);
Получение данных с бирж
Для удобного доступа к биржам есть опенсорсный проект ccxt. С помощью которого возможно в едином стиле обращаться к различным биржам. Однако оказалось, что не все так радужно, по ряду бирж информацию не получалось доставать, и некоторые методы не работали.
В файле create_markets.py происходит инициализация, получаем список криптовалютных пар, по биржам. При этом используется метод load_markets(), который возвращает список пар для биржи.
name_exchange = ["acx", "binance", "bitfinex", "bitfinex2", "wex"]
def create_exchange_and_market_in_db():
exchanges = {}
for id in name_exchange:
exchange = getattr(ccxt, id)
exchanges[id] = exchange()
id_exchage = db_helper.insert_exchage_to_db(exchanges[id],cnx,cursor)
markets = exchanges[id].load_markets()
for mark in markets:
id_market = db_helper.insert_market_to_db( id_exchage, mark, cnx,cursor)
Далее в файле ex_data_saver.py, запускаем сохранение изменение цен для пар:
def save():
markets = db_helper.get_data_exch()
exchanges = {}
for id in name_exchange:
exchange = getattr(ccxt, id)
#isHas = exchange.hasFetchTickers
#if isHas:
exchanges[id] = exchange({
'enableRateLimit': True, # or .enableRateLimit = True later
})
cnx = db_helper.CreateConnection()
cursor = cnx.cursor()
loop = asyncio.get_event_loop()
while True:
start_time = time.time()
input_coroutines = [fetch_ticker(exchanges, name) for name in exchanges]
exch_tickers = loop.run_until_complete(asyncio.gather(*input_coroutines, return_exceptions=True))
count_exchange = 0
delta = time.time() - start_time
for tickers in exch_tickers:
if tickers is not None:
count_exchange+=1
inserted_start = time.time()
db_helper.insert_tick(markets,exch_tickers,cnx,cursor)
inserted_time = time.time()
print(count_exchange," ", delta, ' ', inserted_start - inserted_time)
Асинхронное получение тиков для конкретной пары, происходит с помощью метода ccxt fetchTickers().
async def fetch_ticker(exchanges, name):
item = exchanges[name]
try:
ticker = await item.fetchTickers()
return {name:ticker}
Предварительный анализ данных
Прежде всего интересно на каких биржах и по каким парам, происходит самая активная торговля, нас интересуют ликвидные пары. Для этого нужно подсчитать количество сделок с группировкой по биржам и конкретным парам. В итоге мы получим пары, по которым идет активная торговля.
SELECT ex.name as exchange_name, m.name as market_name, count(*) as count_deals
FROM exchange ex
LEFT JOIN market m ON m.id_exchange = ex.id
LEFT JOIN ticker t ON t.id_market =m.id
GROUP BY ex.id, t.id_market
ORDER BY m.name
HAVING count_deals > 10000;
С помощью SQL запросов, можно находить различные закономерности и отсеивать данные, однако для детального анализа, требуется создание тестового робота, работающего на накопленных с различных бирж данными.
Следующая статья будет посвящена этого робота. И тестового сервера — эмулирующего работу реальной биржи.В тестовый сервер хочу заложить следующие моменты:
- Задержки.
- Проскальзывание.
- Комиссии.
Комментарии (2)
rPman
15.01.2019 01:02Совет, вместо бесполезных тиков и bid/ask (они не дают ответа на вопрос СКОЛЬКО можно обменять по этой цене), собирайте у бирж стаканы — depth, все они в криптоэкономике такой выдают, иногда лимитированный до некоторой глубины, но для нужд арбитража хватит.
Еще больше пользы вы получите, если вместо запроса информации по http REST api, подключайтесь к серверу биржи по websocket (или fix если есть) и восстанавливайте стаканы самостоятельно в реальном времени, без задержек (rest api обычно лимитированы количеством запросов, в конечном счете секунды между ними в среднем), ведь за секунды содержимое стакана изменится, а вы об этом не узнаете.
p.s. я сильно сомневаюсь, что вы сумеете используя sql, делать все это достаточно оперативно, слишком уж много оно накладных расходов дает.
По стакану вы сможете оценить объем сделки и ее реальную стоимость, т.е. например если вы можете на одной бирже по цене 10 купить 100 монет, а на другой по цене 12 продать всего 5, то ваш бот должен на первой купить тоже только пять, иначе на второй бирже вы выставите продажу по 12, и этот ордер на 95 монет останется лимитным, сдвинув курс на ней вниз.
resetme
Несколько абзацев и куски простейшего кода. Для чего статья — не понятно. Мода наверно такая, попробовать новый язык и сразу запилить статейку чтобы не забыть его потом.
Хотя бы PEP8 для начала прочитали перед тем как писать статьи на Хабре.