Выкачиваем информацию с биржи в Excel

Давайте что-нибудь проанализируем.. Например, историю торгов? Это и в принципе полезно, и скиллы набьются полезные… В общем план такой – научиться вытаскивать нужные данные с биржи, экспортировать в Excel, ну и что-нибудь с ними делать. Понятно, что не руками :) Поехали!

Подготовка.

Нам потребуется

а) Установленный питон с модулем requests (как установить читайте тут)

б) Установленный модуль openpyxl – но тут всё просто, запустите командную строку и вбейте pip install openpyxl

Проверка

После того, как вы все установили, давайте проверим, создаются ли валидные Excel файлы. Простейший пример (взятый с официального сайта) показывает, как создать новую книгу, внести туда данные и сохранить:

from openpyxl import Workbook
wb = Workbook()

# Выбрать активную книгу
ws = wb.active

# Запишем число 42 в ячейку А1
ws['A1'] = 42

# Добавим строку с данными
ws.append([1, 2, 3])

# В поле А2 запишем текущую дату и время
import datetime
ws['A2'] = datetime.datetime.now()

# Сохраним файл рядом со скриптом
import os

wb.save(os.path.dirname(os.path.abspath(__file__)) + "/sample.xlsx")

Копируем этот код, вставляем в IDLE (опять же, подробности тут), сохраняем под каким-нибудь именем (у меня это excel_test.py) и запускаем (F5). В папке рядом со скриптом должен появиться файл sample.xlsx. 

Можно открыть его экселем и посмотреть, что внутри:

История торгов из Exmo в Excel


Реклама:


Ок, работает, писать данные можем. Теперь давайте попробуем забрать с exmo.me всю историю торгов. Точнее не так – всю историю Эксмо не дает, а дает максимум 10 000 последних торгов по паре.

Вот код – вставим в IDLE, сохраним как exmo_excel.py и запустим (о том, что такое API и как работать с ним на Exmo читайте в других статьях цикла – ссылки в конце статьи, над комментариями).

import urllib, http.client
import os
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

from openpyxl import Workbook
from datetime import datetime, timezone

# ключи API, которые предоставила exmo
API_KEY = 'K-...'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-...'

# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'

# Свой класс исключений
class ScriptError(Exception):
    pass
class ScriptQuitCondition(Exception):
    pass

# все обращения к API проходят через эту функцию
def call_api(**kwargs):
    payload = {'nonce': int(round(time.time()*1000))}

    if kwargs:
        payload.update(kwargs)
    payload =  urllib.parse.urlencode(payload)

    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
    H.update(payload.encode('utf-8'))
    sign = H.hexdigest()
    
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Key":API_KEY,
           "Sign":sign}
    conn = http.client.HTTPSConnection(API_URL, timeout=60)
    conn.request("POST", "/"+API_VERSION + "/" + kwargs['method'], payload, headers)
    response = conn.getresponse().read()
    
    conn.close()

    try:
        obj = json.loads(response.decode('utf-8'))

        if 'error' in obj and obj['error']:
            raise ScriptError(obj['error'])
        return obj
    except json.decoder.JSONDecodeError:
        raise ScriptError('Ошибка анализа возвращаемых данных, получена строка', response)

# Получим список всех пар, по которым торгует биржа
pairs_list = []
pairs = call_api(method='pair_settings')
for pair in pairs:
    pairs_list.append(pair) # сложим их в словарь

pairs_str = ','.join(pairs_list) # из словаря создадим строку, с парами, разделенными запятыми

# Получим историю торгов по всем парам
trades = call_api(method='user_trades', pair=pairs_str, limit=10000)
for pair in trades: # пройдемся по каждой паре
    if not trades[pair]: #пропускаем пары, по которым не было торгов
        continue
    # Теперь проходим по всем торгам этой пары
    print(pair, len(trades[pair]))

Должны увидеть список пар, по которым торговали, и кол-во полученных сделок по каждой их них. У меня это выглядит так:

Не лишним будет упомянуть, что есть торги по сути. Когда вы выставляете ордер на продажу, например 1 BTC, биржа подбирает для вас покупателей. Ваш ордер может быть исполнен в одну сделку – если кто-то сразу купит ваш биткоин целиком, либо в несколько – когда ваш биткойн раскупят по частям. Так вот, история торгов – это история именно таких сделок.

Вообще, стоило бы сравнить с историей торгов на сайте Эксмо, но там как будто специально неудобно сделано.. В общем, похоже на правду, на этом и остановимся пока. Если что, историю торгов можно смотреть тут (раздел сделки):

Теперь, собственно, нужно объединить оба скрипта, что бы получить историю торгов и выгрузить в эксель. Немного магии и вуаля:

import urllib, http.client
import os
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

from openpyxl import Workbook
from datetime import datetime, timezone

# ключи API, которые предоставила exmo
API_KEY = 'K-...'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-...'

# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'

# Свой класс исключений
class ScriptError(Exception):
    pass
class ScriptQuitCondition(Exception):
    pass

# все обращения к API проходят через эту функцию
def call_api(**kwargs):
    payload = {'nonce': int(round(time.time()*1000))}

    if kwargs:
        payload.update(kwargs)
    payload =  urllib.parse.urlencode(payload)

    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
    H.update(payload.encode('utf-8'))
    sign = H.hexdigest()
    
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Key":API_KEY,
           "Sign":sign}
    conn = http.client.HTTPSConnection(API_URL, timeout=60)
    conn.request("POST", "/"+API_VERSION + "/" + kwargs['method'], payload, headers)
    response = conn.getresponse().read()
    
    conn.close()

    try:
        obj = json.loads(response.decode('utf-8'))

        if 'error' in obj and obj['error']:
            raise ScriptError(obj['error'])
        return obj
    except json.decoder.JSONDecodeError:
        raise ScriptError('Ошибка анализа возвращаемых данных, получена строка', response)

# Получим список всех пар, по которым торгует биржа
pairs_list = []
pairs = call_api(method='pair_settings')
for pair in pairs:
    pairs_list.append(pair) # сложим их в словарь

pairs_str = ','.join(pairs_list) # из словаря создадим строку, с парами, разделенными запятыми

# Создадим Excel файл
wb = Workbook()
ws = wb.active
# Вставим заголовки
ws.append(["Дата сделки", "Пара сделки", "ID ордера", "ID сделки", "Тип сделки", "Кол-во по сделке", "Цена сделки", "Сумма сделки"])

# Получим историю торгов по всем парам
trades = call_api(method='user_trades', pair=pairs_str, limit=10000)
for pair in trades: # пройдемся по каждой паре
    if not trades[pair]: #пропускаем пары, по которым не было торгов
        continue
    # Теперь проходим по всем торгам этой пары
    for trade in trades[pair]:
        # Мы бы могли использовать метод dict.values(), но нам нужны данные в определенном порядке, причем каждый раз для каждого массива, так что немного усложним код
        # Форматируем и вставляем строку с данными в Excel
        ws.append([
            datetime.fromtimestamp(trade['date'], timezone.utc), # дата сделки
            pair, # Пара сделки
            trade['order_id'], # ID ордера
            trade['trade_id'], # ID сделки
            'Покупка' if trade['type'] == 'buy' else 'Продажа',
            float(trade['quantity']), # Кол-во по сделке
            float(trade['price']), # Цена сделки
            float(trade['amount']) * (-1 if trade['type'] == 'buy' else 0.998), # сумма сделки, если buy то отрицательная - так удобнее считать потом
        ])
    
# Сохраняем файл
wb.save(os.path.dirname(os.path.abspath(__file__)) + "/exmo_excel.xlsx")
print('Работу закончил')

Вставляем этот код в IDLE, сохраняем, запускаем.. У вас должен появиться Excel-файл exmo_excel.xlsx рядом со скриптом. Откроем, посмотрим.

Я поставил фильтр по паре LTC_RUB, что бы еще раз акцентировать внимание на сделках, так в файле все торги по всем парам (точнее, последние 10 000 торгов). В первой колонке время сделки (по времени биржи), в остальных вроде понятно, объясню про ID ордера и ID сделки.

Смотреть стоит по времени, т.е. снизу вверх. 14 августа я на почти 150р купил 0, 618LTC по курсу 242,38. Для этого я создавал отложенный ордер (52466257), который был исполнен в рамках одной сделки (5227092).

После этого я, видимо, выставил отложенный ордер на продажу купленного (52466294), который исполнился опять же одной сделкой.

После этого я создал отложенный ордер на покупку (62752648), который был исполнен частями –обратите внимание, что тут две строки с одним и тем же номером ордера и одной и той же ценой, но разными суммами, временем и id сделки. Т.е. сначала кто-то купил почти всё, а потом кто-то еще докупил, что осталось.

Ну а потом сработала еще одна продажа купленного.

Если сложить все суммы сделки (вот почему покупку мы делали отрицательной), то получим сальдо или как там его – мне больше нравится слово профит, хотя и «прибыль» тоже ничего. В данном случае вроде бы 63 копейки прибыли, но….. Тут, насколько я вижу, хотя надо бы и проверить, сумма указывается ДО вычета комиссии биржи – 0.2%.

Если еще раз обратите внимание, то первую сделку я провел за 150 рублей, купив 0,618LTC, а продаю 0,617LTC – потому что часть купленного в LTC съела комиссия (рубли не псотрадали). Когда же я продаю купленное, комиссия берется с рублей – но тут я не вижу, что бы это отражалось. Поэтому, наверное, более точно было считать так (дополнил столбец руками):

Для положительных сумм сделок мы вычитаем комиссию 0.2% (формула видна на рисунке), отрицательные считаем как есть – так правильно. Итого, профит составил 2,8 копейки, юхууу))

Не помню, что я тестил на этой паре год назад, и какие настройки прибыльности стояли, но в общем имейте в виду такую выдачу инфы, что через API, что на сайте.

Если хотите, можете сразу выводить в эксель прибыль за вычетом комиссии. Для этого строку

float(trade['amount']) * (-1 if trade['type'] == 'buy' else 1),

нужно заменить на

float(trade['amount']) * (-1 if trade['type'] == 'buy' else 0.998),

итог будет правильным:

В общем, делайте с экселем теперь что хотите, стройте графики или сводные таблицы, инструмент для получения данных у вас есть.

История торгов из Yobit в Excel

Ну и как бонус давайте сделаем тоже самое для биржи yobit.net. Тут уже будет меньше комментариев, т.к. по сути ничего не меняется, только немного кода. Более детально о том, как работать с API yobit, читайте так же по ссылкам в конце статьи.

В общем, вот код, вбивайте свои ключи, запускайте.. Он будет работать мучительно долго, т.к. во первых очень много пар, а во вторых, после каждой пары добавлено time.sleep(1), что бы вас Yobit не забанил.. Хотя, он может быть и так не забанит, так что можете удалить эту строку и все пойдет шустрее, но это на свой страх и риск.

import os
import json
import requests
import math
import time
import urllib, http.client
import hmac, hashlib

from openpyxl import Workbook
from datetime import datetime, timezone

# Вписываем свои ключи
API_KEY = '...'
API_SECRET = b'...'

"""
    Каждый новый запрос к серверу должен содержать увеличенное число в диапазоне 1-2147483646
    Поэтому храним число в файле поблизости, каждый раз обновляя его
"""
nonce_file = "./nonce"
if not os.path.exists(nonce_file):
    with open(nonce_file, "w") as out:
        out.write('1')
# Будем перехватывать все сообщения об ошибках с биржи
class YobitException(Exception):
    pass
        
def call_api(**kwargs):

    # При каждом обращении к торговому API увеличиваем счетчик nonce на единицу
    with open(nonce_file, 'r+') as inp:
        nonce = int(inp.read())
        inp.seek(0)
        inp.write(str(nonce+1))
        inp.truncate()

    payload = {'nonce': nonce}

    if kwargs:
        payload.update(kwargs)
    payload =  urllib.parse.urlencode(payload)

    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
    H.update(payload.encode('utf-8'))
    sign = H.hexdigest()
    
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Key":API_KEY,
           "Sign":sign}
    conn = http.client.HTTPSConnection("yobit.net", timeout=60)
    conn.request("POST", "/tapi/", payload, headers)
    response = conn.getresponse().read()
    
    conn.close()

    try:
        obj = json.loads(response.decode('utf-8'))

        if 'error' in obj and obj['error']:
            raise YobitException(obj['error'])
        return obj
    except json.decoder.JSONDecodeError:
        raise YobitException('Ошибка анализа возвращаемых данных, получена строка', response)

res = requests.get('https://yobit.net/api/3/info') # получаем данные info
res_obj = json.loads(res.text) # переводим полученный текст в объект с данными

pairs = [pair for pair in res_obj['pairs']] # создадим массив названий пар

# Создадим Excel файл
wb = Workbook()
ws = wb.active
# Вставим заголовки
ws.append(["Дата сделки", "Пара сделки", "ID ордера", "ID сделки", "Тип сделки", "Цена сделки", "Сумма сделки"])

for pair in pairs:
    try:
        print ('Получаем историю торгов по паре %s' % pair, '*'*30)
        data = call_api(method="TradeHistory", pair=pair)
        if(data.get('return')):
            for t in data['return']:
                trade = data['return'][t]
                ws.append([
                    datetime.fromtimestamp(int(trade['timestamp']), timezone.utc), # дата сделки
                    pair, # Пара сделки
                    trade['order_id'], # ID ордера
                    t, # ID сделки
                    'Покупка' if trade['type'] == 'buy' else 'Продажа',
                    float(trade['rate']), # Цена сделки
                    float(trade['amount']) * (-1 if trade['type'] == 'buy' else 1), # сумма сделки, если buy то отрицательная - так удобнее считать потом
                ])
        else:
            print('Торгов не было')
        #time.sleep(1)
    except YobitException as e:
        print("Облом:", e)
    
wb.save(os.path.dirname(os.path.abspath(__file__)) + "/yobit_excel.xlsx")
print('Работу закончил')

Когда оно всё доработает, рядом с файлом появится файл yobit_excel.xslx, можете открывать и делать выводы. Опять же, если нужно вычитать комиссию, то воспользуйтесь советом выше, для эксмо. Если что-то не будет работать или будет работать не так, пишите, поправим.

Удачи!

 

 

Тэги: