Давайте что-нибудь проанализируем.. Например, историю торгов? Это и в принципе полезно, и скиллы набьются полезные… В общем план такой – научиться вытаскивать нужные данные с биржи, экспортировать в 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.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.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, можете открывать и делать выводы. Опять же, если нужно вычитать комиссию, то воспользуйтесь советом выше, для эксмо. Если что-то не будет работать или будет работать не так, пишите, поправим.
Удачи!